<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
	<title>Nette Releases</title>
	<link>https://nette.org/cs/releases</link>
	<language>en</language>
	<category>blog</category>
	<docs>http://backend.userland.com/rss</docs>
	<image>
		<url>https://files.nette.org/images/og-nette.png?v=1641878944</url>
		<title>Nette Releases</title>
		<link>https://nette.org/cs/releases</link>
	</image>
	<atom:link rel="self" href="https://nette.org/cs/releases/rss" type="application/rss+xml" />

	<item>
		<title>Forms v3.3.1</title>
		<link>https://github.com/nette/forms/releases/tag/v3.3.1</link>
		<description>✨ New Features

New Form::Enum rule checks that a value is a case of a backed enum, so invalid input is caught by validation, in the browser too, before it reaches your typed DTO: -&gt;addRule($form::Enum, arg: Status::class)
Event handlers resolve both parameters by their type, so function (array $values, Form $form) works in onSuccess, onError, onClick and onValidate (#345)
%value in error messages reads naturally: uploaded file names, the items of a multi-choice selection, and dates in the control&apos;s format, on the server and in netteForms.js alike (#302)
Rules Filled, Blank and Valid work with any Control implementation, so custom controls no longer need to extend BaseControl to use them (#346)
PHPStan accepts validators with narrowed parameter types in addRule() and addCondition(), and extension methods that take arguments (#350, #354)
PHP 8.6 is supported

🐛 Bug Fixes

Events such as onSuccess can again be fired by calling them as methods (#356)
In Latte, $form points back to the enclosing form after a nested {form} closes
Rule messages and translators may return a Stringable object (#349, #312)
A GET form whose action contains a query parameter without a value (?foo) renders correctly (#348)
netteForms.js validates like the server: lengths count characters, min/max compare numerically, a URL may have a query or fragment without a path, AVIF is a default image type, and the browser&apos;s bad-input check respects the validation scope
Exceeding post_max_size reports its own message, and the Numeric rule has a default message
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>New <strong>Form::Enum</strong> rule checks that a value is a case of a backed enum, so invalid input is caught by validation, in the browser too, before it reaches your typed DTO: <code>-&gt;addRule($form::Enum, arg: Status::class)</code></li>
<li>Event handlers resolve both parameters by their type, so <code>function (array $values, Form $form)</code> works in <code>onSuccess</code>, <code>onError</code>, <code>onClick</code> and <code>onValidate</code> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3252738735" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/345" data-hovercard-type="pull_request" data-hovercard-url="/nette/forms/pull/345/hovercard" href="https://github.com/nette/forms/pull/345">#345</a>)</li>
<li><strong>%value</strong> in error messages reads naturally: uploaded file names, the items of a multi-choice selection, and dates in the control's format, on the server and in netteForms.js alike (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1646252563" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/302" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/302/hovercard" href="https://github.com/nette/forms/issues/302">#302</a>)</li>
<li>Rules <strong>Filled</strong>, <strong>Blank</strong> and <strong>Valid</strong> work with any <code>Control</code> implementation, so custom controls no longer need to extend <code>BaseControl</code> to use them (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3660537160" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/346" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/346/hovercard" href="https://github.com/nette/forms/issues/346">#346</a>)</li>
<li>PHPStan accepts validators with narrowed parameter types in <code>addRule()</code> and <code>addCondition()</code>, and extension methods that take arguments (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4539818765" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/350" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/350/hovercard" href="https://github.com/nette/forms/issues/350">#350</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4869725208" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/354" data-hovercard-type="pull_request" data-hovercard-url="/nette/forms/pull/354/hovercard" href="https://github.com/nette/forms/pull/354">#354</a>)</li>
<li><strong>PHP 8.6</strong> is supported</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Events such as <code>onSuccess</code> can again be fired by calling them as methods (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="5699973662" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/356" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/356/hovercard" href="https://github.com/nette/forms/issues/356">#356</a>)</li>
<li>In Latte, <code>$form</code> points back to the enclosing form after a nested <code>{form}</code> closes</li>
<li>Rule messages and translators may return a <code>Stringable</code> object (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3973575164" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/349" data-hovercard-type="pull_request" data-hovercard-url="/nette/forms/pull/349/hovercard" href="https://github.com/nette/forms/pull/349">#349</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2021432649" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/312" data-hovercard-type="pull_request" data-hovercard-url="/nette/forms/pull/312/hovercard" href="https://github.com/nette/forms/pull/312">#312</a>)</li>
<li>A GET form whose action contains a query parameter without a value (<code>?foo</code>) renders correctly (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3699349899" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/348" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/348/hovercard" href="https://github.com/nette/forms/issues/348">#348</a>)</li>
<li>netteForms.js validates like the server: lengths count characters, min/max compare numerically, a URL may have a query or fragment without a path, AVIF is a default image type, and the browser's bad-input check respects the validation scope</li>
<li>Exceeding <code>post_max_size</code> reports its own message, and the <code>Numeric</code> rule has a default message</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 29 Oct 2026 03:59:34 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/forms/releases/tag/v3.3.1</guid>
	</item>
	<item>
		<title>Forms v3.2.10</title>
		<link>https://github.com/nette/forms/releases/tag/v3.2.10</link>
		<description>✨ New Features

PHP 8.6 is supported
%value in error messages now reads naturally for every control: uploaded file names, the items of a multi-choice selection joined by commas, and dates in the control&apos;s format (#302)
Rules Filled, Blank and Valid work with any Control implementation, so custom controls no longer need to extend BaseControl to use them (#346)

🐛 Bug Fixes

Rule messages and translators may return a Stringable object; validation messages, select optgroups and the prompt now accept it (#349, #312)
Form values map onto int-backed enum properties: numeric strings from text and hidden fields convert to the matching case, and a value with no matching case is passed on unchanged
A GET form whose action contains a query parameter without a value (?foo) renders correctly (#348)
Exceeding post_max_size reports its own message instead of the one for file size
A Form or Container subclass that applies the SmartObject trait again works without a fatal error (nette/utils#338)
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li><strong>PHP 8.6</strong> is supported</li>
<li><strong>%value</strong> in error messages now reads naturally for every control: uploaded file names, the items of a multi-choice selection joined by commas, and dates in the control's format (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1646252563" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/302" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/302/hovercard" href="https://github.com/nette/forms/issues/302">#302</a>)</li>
<li>Rules <strong>Filled</strong>, <strong>Blank</strong> and <strong>Valid</strong> work with any <code>Control</code> implementation, so custom controls no longer need to extend <code>BaseControl</code> to use them (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3660537160" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/346" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/346/hovercard" href="https://github.com/nette/forms/issues/346">#346</a>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Rule messages and translators may return a <code>Stringable</code> object; validation messages, select optgroups and the prompt now accept it (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3973575164" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/349" data-hovercard-type="pull_request" data-hovercard-url="/nette/forms/pull/349/hovercard" href="https://github.com/nette/forms/pull/349">#349</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2021432649" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/312" data-hovercard-type="pull_request" data-hovercard-url="/nette/forms/pull/312/hovercard" href="https://github.com/nette/forms/pull/312">#312</a>)</li>
<li>Form values map onto int-backed enum properties: numeric strings from text and hidden fields convert to the matching case, and a value with no matching case is passed on unchanged</li>
<li>A GET form whose action contains a query parameter without a value (<code>?foo</code>) renders correctly (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3699349899" data-permission-text="Title is private" data-url="https://github.com/nette/forms/issues/348" data-hovercard-type="issue" data-hovercard-url="/nette/forms/issues/348/hovercard" href="https://github.com/nette/forms/issues/348">#348</a>)</li>
<li>Exceeding <code>post_max_size</code> reports its own message instead of the one for file size</li>
<li>A <code>Form</code> or <code>Container</code> subclass that applies the <code>SmartObject</code> trait again works without a fatal error (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4577961186" data-permission-text="Title is private" data-url="https://github.com/nette/utils/issues/338" data-hovercard-type="issue" data-hovercard-url="/nette/utils/issues/338/hovercard" href="https://github.com/nette/utils/issues/338">nette/utils#338</a>)</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 29 Oct 2026 03:21:20 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/forms/releases/tag/v3.2.10</guid>
	</item>
	<item>
		<title>Component Model v3.2.1</title>
		<link>https://github.com/nette/component-model/releases/tag/v3.2.1</link>
		<description>
Ready for PHP 8.6 – the supported range is now PHP 8.1 to 8.6
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Ready for <strong>PHP 8.6</strong> – the supported range is now PHP 8.1 to 8.6</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 29 Oct 2026 02:52:05 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/component-model/releases/tag/v3.2.1</guid>
	</item>
	<item>
		<title>Bootstrap v3.3.1</title>
		<link>https://github.com/nette/bootstrap/releases/tag/v3.3.1</link>
		<description>
Ready for PHP 8.6
Works with nette/neon 4.0 as well as 3.4
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Ready for <strong>PHP 8.6</strong></li>
<li>Works with <strong>nette/neon 4.0</strong> as well as 3.4</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 28 Oct 2026 02:45:19 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/bootstrap/releases/tag/v3.3.1</guid>
	</item>
	<item>
		<title>Safe Stream v3.0.5</title>
		<link>https://github.com/nette/safe-stream/releases/tag/v3.0.5</link>
		<description>
Ready for PHP 8.6 – SafeStream now officially supports PHP 8.0 through 8.6
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Ready for <strong>PHP 8.6</strong> – SafeStream now officially supports PHP 8.0 through 8.6</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 28 Oct 2026 00:38:46 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/safe-stream/releases/tag/v3.0.5</guid>
	</item>
	<item>
		<title>Database v3.2.10</title>
		<link>https://github.com/nette/database/releases/tag/v3.2.10</link>
		<description>✨ New Features

Ready for PHP 8.6
insert([]) now inserts a row of database defaults on PostgreSQL, SQLite and MS SQL too, not only on MySQL, so saving an empty form works on every engine

🐛 Bug Fixes

Floats keep their full value, both as bound parameters and inlined in SQL; 1/3 or 1e-11 reach the database exactly as they are in PHP
Selection::insert() with a list of rows returns the number of inserted rows, as documented; code that used the returned ActiveRow now gets an int (#330)
transaction() rethrows the original exception even when the final ROLLBACK fails, e.g. after a deadlock
GroupedSelection::limit() respects the offset when the selection belongs to multiple parent rows, and a Selection over a table without a primary key can be re-queried
Conditions skipped by a short-circuited ?and / ?or no longer leave their parameters behind
A where() identical to an existing JOIN condition is no longer dropped, and binary parameters no longer make distinct conditions collide
Row: isset() and offsetExists() give correct answers, including for falsy values
Reflection is more accurate across drivers: column order of composite foreign keys and indexes (MySQL, PostgreSQL), column defaults (PostgreSQL, #329), primary key and identity columns (MS SQL), tables without an explicit schema (MS SQL), autoincrement detection (SQLite) and table resolution along search_path (PostgreSQL)
MS SQL: identifiers containing [ or ] are escaped correctly, and offset-only or zero-limit queries generate valid SQL
The Tracy panel no longer shows duplicate BlueScreen SQL sections with multiple connections

🛡️ Robustness

Constraint violations on SQL Server, CHECK violations on SQLite and more connection-loss codes on PostgreSQL and MySQL now map to the specific exception classes
Misuse reports a clear exception instead of a PHP error: an unknown PDO driver, page() with less than one item per page, related() on a composite primary key, getInsertId() on a failed lazy connection, an unknown table in Reflection on SQLite, an unknown constant in the DI options; the ambiguous-reference message names the table, key and candidates
The DI extension detects a single connection by the presence of dsn, so key order in the config no longer matters
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>Ready for <strong>PHP 8.6</strong></li>
<li><strong>insert([])</strong> now inserts a row of database defaults on PostgreSQL, SQLite and MS SQL too, not only on MySQL, so saving an empty form works on every engine</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Floats keep their full value, both as bound parameters and inlined in SQL; <code>1/3</code> or <code>1e-11</code> reach the database exactly as they are in PHP</li>
<li><strong>Selection::insert()</strong> with a list of rows returns the number of inserted rows, as documented; code that used the returned ActiveRow now gets an <code>int</code> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4588325173" data-permission-text="Title is private" data-url="https://github.com/nette/database/issues/330" data-hovercard-type="pull_request" data-hovercard-url="/nette/database/pull/330/hovercard" href="https://github.com/nette/database/pull/330">#330</a>)</li>
<li><strong>transaction()</strong> rethrows the original exception even when the final ROLLBACK fails, e.g. after a deadlock</li>
<li><strong>GroupedSelection::limit()</strong> respects the offset when the selection belongs to multiple parent rows, and a Selection over a table without a primary key can be re-queried</li>
<li>Conditions skipped by a short-circuited <code>?and</code> / <code>?or</code> no longer leave their parameters behind</li>
<li>A <code>where()</code> identical to an existing JOIN condition is no longer dropped, and binary parameters no longer make distinct conditions collide</li>
<li><strong>Row</strong>: <code>isset()</code> and <code>offsetExists()</code> give correct answers, including for falsy values</li>
<li>Reflection is more accurate across drivers: column order of composite foreign keys and indexes (MySQL, PostgreSQL), column defaults (PostgreSQL, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4350332173" data-permission-text="Title is private" data-url="https://github.com/nette/database/issues/329" data-hovercard-type="issue" data-hovercard-url="/nette/database/issues/329/hovercard" href="https://github.com/nette/database/issues/329">#329</a>), primary key and identity columns (MS SQL), tables without an explicit schema (MS SQL), autoincrement detection (SQLite) and table resolution along <code>search_path</code> (PostgreSQL)</li>
<li>MS SQL: identifiers containing <code>[</code> or <code>]</code> are escaped correctly, and offset-only or zero-limit queries generate valid SQL</li>
<li>The Tracy panel no longer shows duplicate BlueScreen SQL sections with multiple connections</li>
</ul>
<h2>🛡️ Robustness</h2>
<ul>
<li>Constraint violations on SQL Server, CHECK violations on SQLite and more connection-loss codes on PostgreSQL and MySQL now map to the specific exception classes</li>
<li>Misuse reports a clear exception instead of a PHP error: an unknown PDO driver, <code>page()</code> with less than one item per page, <code>related()</code> on a composite primary key, <code>getInsertId()</code> on a failed lazy connection, an unknown table in Reflection on SQLite, an unknown constant in the DI options; the ambiguous-reference message names the table, key and candidates</li>
<li>The DI extension detects a single connection by the presence of <code>dsn</code>, so key order in the config no longer matters</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 27 Oct 2026 21:50:45 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/database/releases/tag/v3.2.10</guid>
	</item>
	<item>
		<title>Caching v3.4.3</title>
		<link>https://github.com/nette/caching/releases/tag/v3.4.3</link>
		<description>✨ New Features

Ready for PHP 8.6
SQLiteStorage now cleans up after itself – expired items are removed by probabilistic garbage collection, just like in FileStorage (#83)

🐛 Bug Fixes

FileStorage: an Items dependency on an item that is being generated at the same moment no longer hangs the process (#54)
FileStorage: cleaning the cache leaves alone files and directories of other tools sharing the cache directory, such as Latte, and copes safely with any foreign file it comes across (#45)
MemcachedStorage: items with an expiration longer than 30 days are now kept for the intended time
SQLiteStorage: bulkRead() works with any number of keys, regardless of the SQLite limit of query parameters

🛡️ Robustness

PsrCacheAdapter follows PSR-16 more closely: a zero or negative TTL deletes the item, and a DateInterval TTL is converted independently of the timezone
Edge cases in storages: a non-positive expiration in MemcachedStorage removes the item, SQLiteJournal keeps priority 0, SQLiteStorage ignores Sliding without Expire like the other storages, and SQLite transactions are rolled back on failure
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>Ready for PHP 8.6</li>
<li><strong>SQLiteStorage</strong> now cleans up after itself – expired items are removed by probabilistic garbage collection, just like in FileStorage (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3141852516" data-permission-text="Title is private" data-url="https://github.com/nette/caching/issues/83" data-hovercard-type="issue" data-hovercard-url="/nette/caching/issues/83/hovercard" href="https://github.com/nette/caching/issues/83">#83</a>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>FileStorage: an <code>Items</code> dependency on an item that is being generated at the same moment no longer hangs the process (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="294199391" data-permission-text="Title is private" data-url="https://github.com/nette/caching/issues/54" data-hovercard-type="issue" data-hovercard-url="/nette/caching/issues/54/hovercard" href="https://github.com/nette/caching/issues/54">#54</a>)</li>
<li>FileStorage: cleaning the cache leaves alone files and directories of other tools sharing the cache directory, such as Latte, and copes safely with any foreign file it comes across (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="174887353" data-permission-text="Title is private" data-url="https://github.com/nette/caching/issues/45" data-hovercard-type="issue" data-hovercard-url="/nette/caching/issues/45/hovercard" href="https://github.com/nette/caching/issues/45">#45</a>)</li>
<li>MemcachedStorage: items with an expiration longer than 30 days are now kept for the intended time</li>
<li>SQLiteStorage: <code>bulkRead()</code> works with any number of keys, regardless of the SQLite limit of query parameters</li>
</ul>
<h2>🛡️ Robustness</h2>
<ul>
<li><strong>PsrCacheAdapter</strong> follows PSR-16 more closely: a zero or negative TTL deletes the item, and a <code>DateInterval</code> TTL is converted independently of the timezone</li>
<li>Edge cases in storages: a non-positive expiration in MemcachedStorage removes the item, SQLiteJournal keeps priority 0, SQLiteStorage ignores <code>Sliding</code> without <code>Expire</code> like the other storages, and SQLite transactions are rolled back on failure</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 27 Oct 2026 18:41:44 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/caching/releases/tag/v3.4.3</guid>
	</item>
	<item>
		<title>Component Model v4.0.2</title>
		<link>https://github.com/nette/component-model/releases/tag/v4.0.2</link>
		<description>
Supports PHP 8.6
Removed the internal _isCloning() method; no code outside the library calls it
lookup() and lookupPath() always answer from the current tree: the root is found correctly after the tree is attached higher up, and a cloned component finds its cloned ancestors instead of the original ones
An exception thrown from a monitor() callback now cancels the change cleanly: the component stays where it was and the callbacks that already ran get their counterpart, which is what forbidding a form nested in another form relies on
Callbacks that change the tree themselves – remove or move their own component, a sibling or an ancestor – keep the tree, lookup() and the attached/detached notifications consistent
removeComponent() detaches the component before dropping it from the container, so $detached callbacks still see it in its place, and lookup() inside them still finds the ancestor being left
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Supports <strong>PHP 8.6</strong></li>
<li>Removed the internal <strong>_isCloning()</strong> method; no code outside the library calls it</li>
<li><strong>lookup()</strong> and <strong>lookupPath()</strong> always answer from the current tree: the root is found correctly after the tree is attached higher up, and a cloned component finds its cloned ancestors instead of the original ones</li>
<li>An exception thrown from a <strong>monitor()</strong> callback now cancels the change cleanly: the component stays where it was and the callbacks that already ran get their counterpart, which is what forbidding a form nested in another form relies on</li>
<li>Callbacks that change the tree themselves – remove or move their own component, a sibling or an ancestor – keep the tree, <code>lookup()</code> and the attached/detached notifications consistent</li>
<li><strong>removeComponent()</strong> detaches the component before dropping it from the container, so <code>$detached</code> callbacks still see it in its place, and <code>lookup()</code> inside them still finds the ancestor being left</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 27 Oct 2026 01:44:34 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/component-model/releases/tag/v4.0.2</guid>
	</item>
	<item>
		<title>Tester v2.7.0</title>
		<link>https://github.com/nette/tester/releases/tag/v2.7.0</link>
		<description>Tester 2.7 makes itself at home in CI: failures land right in the pull request diff, hanging tests no longer hang the pipeline, and slow tests have nowhere to hide.
✨ New Features

GitHub Actions annotations – the new -o github output marks failed tests directly in the PR diff view, and it switches on automatically when Tester runs on GitHub Actions, so there is nothing to configure
Test time limit – --timeout &lt;seconds&gt; sets a limit for every test, @timeout overrides it per file; a test that runs over is terminated and reported as a failure instead of blocking the whole run
--slowest – prints the 10 (or as many as you ask for) slowest tests after the run, so you know exactly where the time goes
#[DataProvider] and #[Throws] attributes – TestCase methods can now use PHP attributes instead of docblock annotations; the annotations keep working
HttpAssert::fetch() accepts a timeout (30 seconds by default), so an unresponsive server can&apos;t stall a test
JUnit reports now include test durations, for failed and skipped tests as well
Faster cold start – TestCase methods are discovered in parallel with other tests, and each test file&apos;s annotations are parsed only once

💥 Breaking Changes

PHP 8.1 is now the minimum required version
Environment::skip(), Environment::exit() and TestCase::skip() now return never; a subclass overriding them must change its return type too
The tester command exits with a non-zero code when it finds no tests, so a mistyped path no longer passes in CI
A TestCase data provider that returns no data sets is now an error, just like an empty file-level provider
Assertion type &apos;integer&apos; in Assert::type() is deprecated, use &apos;int&apos;

🐛 Bug Fixes

TAP and JUnit outputs no longer contain ANSI color sequences
Environment::lock() reports an error when the lock directory does not exist
</description>
		<content:encoded><![CDATA[
		<p>Tester 2.7 makes itself at home in CI: failures land right in the pull request diff, hanging tests no longer hang the pipeline, and slow tests have nowhere to hide.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>GitHub Actions annotations</strong> – the new <code>-o github</code> output marks failed tests directly in the PR diff view, and it switches on automatically when Tester runs on GitHub Actions, so there is nothing to configure</li>
<li><strong>Test time limit</strong> – <code>--timeout &lt;seconds&gt;</code> sets a limit for every test, <code>@timeout</code> overrides it per file; a test that runs over is terminated and reported as a failure instead of blocking the whole run</li>
<li><strong><code>--slowest</code></strong> – prints the 10 (or as many as you ask for) slowest tests after the run, so you know exactly where the time goes</li>
<li><strong><code>#[DataProvider]</code> and <code>#[Throws]</code> attributes</strong> – <code>TestCase</code> methods can now use PHP attributes instead of docblock annotations; the annotations keep working</li>
<li><strong><code>HttpAssert::fetch()</code></strong> accepts a <code>timeout</code> (30 seconds by default), so an unresponsive server can't stall a test</li>
<li><strong>JUnit reports</strong> now include test durations, for failed and skipped tests as well</li>
<li><strong>Faster cold start</strong> – <code>TestCase</code> methods are discovered in parallel with other tests, and each test file's annotations are parsed only once</li>
</ul>
<h2>💥 Breaking Changes</h2>
<ul>
<li><strong>PHP 8.1</strong> is now the minimum required version</li>
<li><code>Environment::skip()</code>, <code>Environment::exit()</code> and <code>TestCase::skip()</code> now return <code>never</code>; a subclass overriding them must change its return type too</li>
<li>The <code>tester</code> command exits with a non-zero code when it finds no tests, so a mistyped path no longer passes in CI</li>
<li>A <code>TestCase</code> data provider that returns no data sets is now an error, just like an empty file-level provider</li>
<li>Assertion type <code>'integer'</code> in <code>Assert::type()</code> is deprecated, use <code>'int'</code></li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>TAP and JUnit outputs no longer contain ANSI color sequences</li>
<li><code>Environment::lock()</code> reports an error when the lock directory does not exist</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 26 Oct 2026 22:25:40 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tester/releases/tag/v2.7.0</guid>
	</item>
	<item>
		<title>Php Generator v4.2.4</title>
		<link>https://github.com/nette/php-generator/releases/tag/v4.2.4</link>
		<description>🐛 Bug Fixes

fromCode() now keeps a file comment placed before declare(strict_types=1) (#182)
Extracting method and property hook bodies ignores the members of anonymous classes nested inside them
PropertyHookType is now an alias of PropertyAccessMode, so both enums are interchangeable wherever hooks are added or looked up

🛡️ Robustness

Invalid declarations now report a clear error when printed: a readonly property that is static or has a default value, a final private constant, an abstract final property hook, and an enum whose backing type is not int or string or whose case values do not match it
setHooks() validates hook types, and the presence of php-parser 5 is detected reliably, with a clear message when an older version is installed
</description>
		<content:encoded><![CDATA[
		<h2>🐛 Bug Fixes</h2>
<ul>
<li><code>fromCode()</code> now keeps a file comment placed before <code>declare(strict_types=1)</code> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4017794327" data-permission-text="Title is private" data-url="https://github.com/nette/php-generator/issues/182" data-hovercard-type="pull_request" data-hovercard-url="/nette/php-generator/pull/182/hovercard" href="https://github.com/nette/php-generator/pull/182">#182</a>)</li>
<li>Extracting method and property hook bodies ignores the members of anonymous classes nested inside them</li>
<li><code>PropertyHookType</code> is now an alias of <code>PropertyAccessMode</code>, so both enums are interchangeable wherever hooks are added or looked up</li>
</ul>
<h2>🛡️ Robustness</h2>
<ul>
<li>Invalid declarations now report a clear error when printed: a readonly property that is static or has a default value, a <code>final private</code> constant, an <code>abstract final</code> property hook, and an enum whose backing type is not int or string or whose case values do not match it</li>
<li><code>setHooks()</code> validates hook types, and the presence of php-parser 5 is detected reliably, with a clear message when an older version is installed</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 26 Oct 2026 22:18:30 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/php-generator/releases/tag/v4.2.4</guid>
	</item>
	<item>
		<title>Routing v3.1.5</title>
		<link>https://github.com/nette/routing/releases/tag/v3.1.5</link>
		<description>
PHP 8.6 support
RouteList with withDomain() or withPath() no longer keeps growing its internal cache in long-running applications (workers like FrankenPHP or RoadRunner)
constructUrl() with an array or object as a path parameter now skips the route instead of throwing a TypeError
</description>
		<content:encoded><![CDATA[
		<ul>
<li>PHP 8.6 support</li>
<li><code>RouteList</code> with <code>withDomain()</code> or <code>withPath()</code> no longer keeps growing its internal cache in long-running applications (workers like FrankenPHP or RoadRunner)</li>
<li><code>constructUrl()</code> with an array or object as a path parameter now skips the route instead of throwing a <code>TypeError</code></li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 26 Oct 2026 22:00:49 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/routing/releases/tag/v3.1.5</guid>
	</item>
	<item>
		<title>Di v3.2.8</title>
		<link>https://github.com/nette/di/releases/tag/v3.2.8</link>
		<description>✨ New Features

Support for PHP 8.6
Support for nette/neon 4.0: configuration files are read the same way as with 3.x, which keeps working
#[SensitiveParameter] now hides arrays and other non-scalar arguments too, so database credentials passed as an array no longer show up in Tracy&apos;s source snippets
Nette\DI\Definitions\Definition now lives at Nette\DI\Definition; the old name keeps working as an alias

💥 Breaking Changes

Locator definitions are checked at compile time. Every reference must match a get*() or create*() method of the interface, and every method with a non-nullable return type must have its reference. A typo in a key now fails compilation with a message naming the reference or method, where it used to compile and throw MissingServiceException only on the first call. Fix the key, or make the method&apos;s return type nullable if the service is truly optional. Interfaces with a generic get($name) are exempt.
Service names may no longer contain __, which is reserved for encoding dots in the names of generated methods.

🐛 Bug Fixes

Locator methods with an acronym work with the natural key: getPDO() finds the reference pdo (and still pDO), the same for getURL(), getDB() and the like
Container::createInstance() and callMethod() pass the actual value to a scalar parameter marked #[SensitiveParameter]
getServiceDescriptors() reports a service named PDO under its real name instead of pDO
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>Support for PHP 8.6</li>
<li>Support for <strong>nette/neon 4.0</strong>: configuration files are read the same way as with 3.x, which keeps working</li>
<li><strong><code>#[SensitiveParameter]</code> now hides arrays and other non-scalar arguments too</strong>, so database credentials passed as an array no longer show up in Tracy's source snippets</li>
<li><code>Nette\DI\Definitions\Definition</code> now lives at <strong><code>Nette\DI\Definition</code></strong>; the old name keeps working as an alias</li>
</ul>
<h2>💥 Breaking Changes</h2>
<ul>
<li><strong>Locator definitions are checked at compile time.</strong> Every reference must match a <code>get*()</code> or <code>create*()</code> method of the interface, and every method with a non-nullable return type must have its reference. A typo in a key now fails compilation with a message naming the reference or method, where it used to compile and throw <code>MissingServiceException</code> only on the first call. Fix the key, or make the method's return type nullable if the service is truly optional. Interfaces with a generic <code>get($name)</code> are exempt.</li>
<li>Service names may no longer contain <code>__</code>, which is reserved for encoding dots in the names of generated methods.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Locator methods with an acronym work with the natural key: <code>getPDO()</code> finds the reference <code>pdo</code> (and still <code>pDO</code>), the same for <code>getURL()</code>, <code>getDB()</code> and the like</li>
<li><code>Container::createInstance()</code> and <code>callMethod()</code> pass the actual value to a scalar parameter marked <code>#[SensitiveParameter]</code></li>
<li><code>getServiceDescriptors()</code> reports a service named <code>PDO</code> under its real name instead of <code>pDO</code></li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 26 Oct 2026 15:50:33 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/di/releases/tag/v3.2.8</guid>
	</item>
	<item>
		<title>Neon v4.0.0</title>
		<link>https://github.com/nette/neon/releases/tag/v4.0.0</link>
		<description>NEON 4 parses a file into a lossless syntax tree in which every comment and every space has its place, so you can edit a configuration and the diff shows only your change. Decoding and encoding stay as they were: Neon::decode() gives the same values as 3.4.
💥 Breaking Changes

Requires PHP 8.4 or newer and the mbstring extension
The tree API is new: Neon::parse() returns a Nodes\DocumentNode, and the classes Decoder, Node\* and the old Traverser are gone. Code that walked the old nodes moves to the new tree, see examples/tree
Neon::encode() throws Nette\Neon\Exception for a string that is not valid UTF-8 instead of replacing it with U+FFFD; its errors now name the path to the value
Some error messages are more precise; code that matches their text may need an update
neon-lint has a new command-line contract: --debug is gone, and a failure of the tool itself exits with 2
Neon::BLOCK and Neon::CHAIN are deprecated, use blockMode: true and Neon::Chain

✨ New Features

Lossless parsing – Neon::parse($text)-&gt;print() === $text holds for any input NEON accepts
Format-preserving editing – setValue(), addItem() and removeItem() change only the tokens they edit: 0x0CEA stays hexadecimal, yes becomes no, a new key is indented like its siblings, and a removed item takes its comment along. A refused edit changes nothing at all, so installers, admin panels and AI agents can rewrite config.neon safely
A navigable tree – nodes know their parent, their comments and their position (line, column, offset); find(), findAncestor(), siblings, and a public Traverser that can replace and remove nodes on the walk
Evaluator – subclass it to turn literals, strings or entities into your own values, such as constants or parameters, the way the Nette DI container reads its configuration
Neon::encode() accepts a closure as $blockMode to decide per array whether it is written as a block, e.g. fn($v, $path) =&gt; !$path for the first level only, and writes floats in the shortest form that reads back exactly
Exception carries the position of the problem as an object and the bare message via getDescription()
neon-lint reports one line per finding, --json for tools and --check to verify that a file prints back byte for byte; an AI agent can run it after saving a .neon file
Runnable examples with their real output document the whole API
The format, the tree and the editing semantics follow a language-neutral specification shared with the JavaScript implementation @nette/neon
</description>
		<content:encoded><![CDATA[
		<p>NEON 4 parses a file into a lossless syntax tree in which every comment and every space has its place, so you can edit a configuration and the diff shows only your change. Decoding and encoding stay as they were: <code>Neon::decode()</code> gives the same values as 3.4.</p>
<h2>💥 Breaking Changes</h2>
<ul>
<li>Requires PHP 8.4 or newer and the <code>mbstring</code> extension</li>
<li>The tree API is new: <strong>Neon::parse()</strong> returns a <code>Nodes\DocumentNode</code>, and the classes <code>Decoder</code>, <code>Node\*</code> and the old <code>Traverser</code> are gone. Code that walked the old nodes moves to the new tree, see <a href="/nette/neon/blob/v4.0.0/examples/tree">examples/tree</a></li>
<li><strong>Neon::encode()</strong> throws <code>Nette\Neon\Exception</code> for a string that is not valid UTF-8 instead of replacing it with U+FFFD; its errors now name the path to the value</li>
<li>Some error messages are more precise; code that matches their text may need an update</li>
<li><strong>neon-lint</strong> has a new command-line contract: <code>--debug</code> is gone, and a failure of the tool itself exits with 2</li>
<li><code>Neon::BLOCK</code> and <code>Neon::CHAIN</code> are deprecated, use <code>blockMode: true</code> and <code>Neon::Chain</code></li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong>Lossless parsing</strong> – <code>Neon::parse($text)-&gt;print() === $text</code> holds for any input NEON accepts</li>
<li><strong>Format-preserving editing</strong> – <code>setValue()</code>, <code>addItem()</code> and <code>removeItem()</code> change only the tokens they edit: <code>0x0CEA</code> stays hexadecimal, <code>yes</code> becomes <code>no</code>, a new key is indented like its siblings, and a removed item takes its comment along. A refused edit changes nothing at all, so installers, admin panels and AI agents can rewrite <code>config.neon</code> safely</li>
<li><strong>A navigable tree</strong> – nodes know their parent, their comments and their position (line, column, offset); <code>find()</code>, <code>findAncestor()</code>, siblings, and a public <strong>Traverser</strong> that can replace and remove nodes on the walk</li>
<li><strong>Evaluator</strong> – subclass it to turn literals, strings or entities into your own values, such as constants or parameters, the way the Nette DI container reads its configuration</li>
<li><strong>Neon::encode()</strong> accepts a closure as <code>$blockMode</code> to decide per array whether it is written as a block, e.g. <code>fn($v, $path) =&gt; !$path</code> for the first level only, and writes floats in the shortest form that reads back exactly</li>
<li><strong>Exception</strong> carries the position of the problem as an object and the bare message via <code>getDescription()</code></li>
<li><strong>neon-lint</strong> reports one line per finding, <code>--json</code> for tools and <code>--check</code> to verify that a file prints back byte for byte; an AI agent can run it after saving a <code>.neon</code> file</li>
<li>Runnable <a href="/nette/neon/blob/v4.0.0/examples">examples</a> with their real output document the whole API</li>
<li>The format, the tree and the editing semantics follow a language-neutral <a href="https://github.com/nette/neon-specification">specification</a> shared with the JavaScript implementation <a href="https://github.com/nette/neon-js">@nette/neon</a></li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 26 Oct 2026 00:19:49 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/neon/releases/tag/v4.0.0</guid>
	</item>
	<item>
		<title>Neon v3.4.10</title>
		<link>https://github.com/nette/neon/releases/tag/v3.4.10</link>
		<description>🐛 Bug Fixes

Neon::encode() now quotes strings like -.5 and +.5, so they decode back as strings, not floats
Multiline strings whose first line starts with whitespace, or with a line starting with &apos;&apos;&apos;, now survive an encode and decode round trip unchanged
neon-lint no longer mistakes --debug for the path to check

🛡️ Robustness

The parser holds up against hostile input: nesting deeper than 500 levels throws Too deep nesting instead of overflowing the stack, and deeply nested dash lists no longer take exponential time to parse
Error messages count the column in characters rather than bytes, and their excerpts never cut a multibyte character in half
</description>
		<content:encoded><![CDATA[
		<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Neon::encode()</strong> now quotes strings like <code>-.5</code> and <code>+.5</code>, so they decode back as strings, not floats</li>
<li>Multiline strings whose first line starts with whitespace, or with a line starting with <code>'''</code>, now survive an encode and decode round trip unchanged</li>
<li><strong>neon-lint</strong> no longer mistakes <code>--debug</code> for the path to check</li>
</ul>
<h2>🛡️ Robustness</h2>
<ul>
<li>The parser holds up against hostile input: nesting deeper than 500 levels throws <code>Too deep nesting</code> instead of overflowing the stack, and deeply nested dash lists no longer take exponential time to parse</li>
<li>Error messages count the column in characters rather than bytes, and their excerpts never cut a multibyte character in half</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 25 Oct 2026 23:03:38 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/neon/releases/tag/v3.4.10</guid>
	</item>
	<item>
		<title>Robot Loader v4.1.4</title>
		<link>https://github.com/nette/robot-loader/releases/tag/v4.1.4</link>
		<description>
RobotLoader is ready for PHP 8.6
</description>
		<content:encoded><![CDATA[
		<ul>
<li>RobotLoader is ready for <strong>PHP 8.6</strong></li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 25 Oct 2026 16:51:42 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/robot-loader/releases/tag/v4.1.4</guid>
	</item>
	<item>
		<title>Http v3.4.2</title>
		<link>https://github.com/nette/http/releases/tag/v3.4.2</link>
		<description>✨ New Features

PHP 8.6 is officially supported
Static analysis now knows that getQuery() and getPost() without a key return an array of all parameters
IResponse::setCookie() declares the $sameSite and $partitioned parameters, so code typed against the interface passes static analysis when using them (#247)

🐛 Bug Fixes

getQuery(null) and getPost(null) return all parameters, the same as calling them without an argument
getDomain() of Url and UrlImmutable returns IPv6 addresses with an embedded IPv4 part ([::ffff:192.0.2.1]) and 0.0.0.0 whole instead of splitting them at the dots (#241)
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>PHP 8.6 is officially supported</li>
<li>Static analysis now knows that <strong>getQuery()</strong> and <strong>getPost()</strong> without a key return an array of all parameters</li>
<li><strong>IResponse::setCookie()</strong> declares the <code>$sameSite</code> and <code>$partitioned</code> parameters, so code typed against the interface passes static analysis when using them (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4066705737" data-permission-text="Title is private" data-url="https://github.com/nette/http/issues/247" data-hovercard-type="pull_request" data-hovercard-url="/nette/http/pull/247/hovercard" href="https://github.com/nette/http/pull/247">#247</a>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>getQuery(null)</strong> and <strong>getPost(null)</strong> return all parameters, the same as calling them without an argument</li>
<li><strong>getDomain()</strong> of <code>Url</code> and <code>UrlImmutable</code> returns IPv6 addresses with an embedded IPv4 part (<code>[::ffff:192.0.2.1]</code>) and <code>0.0.0.0</code> whole instead of splitting them at the dots (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2713856379" data-permission-text="Title is private" data-url="https://github.com/nette/http/issues/241" data-hovercard-type="pull_request" data-hovercard-url="/nette/http/pull/241/hovercard" href="https://github.com/nette/http/pull/241">#241</a>)</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 23 Oct 2026 13:58:49 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/http/releases/tag/v3.4.2</guid>
	</item>
	<item>
		<title>Http v3.3.5</title>
		<link>https://github.com/nette/http/releases/tag/v3.3.5</link>
		<description>✨ New Features

Ready for PHP 8.6

🐛 Bug Fixes

Security: the client address behind a trusted proxy is now taken from the rightmost untrusted hop of Forwarded / X-Forwarded-For, so a client cannot spoof it by prepending its own entry. Scheme and host are read from that same hop, and getRemoteAddress() returns null when the forwarded value is not a valid IP.
UserStorage::setNamespace() now works when switching to another namespace after the storage has been used
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>Ready for <strong>PHP 8.6</strong></li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Security:</strong> the client address behind a trusted proxy is now taken from the rightmost untrusted hop of <code>Forwarded</code> / <code>X-Forwarded-For</code>, so a client cannot spoof it by prepending its own entry. Scheme and host are read from that same hop, and <code>getRemoteAddress()</code> returns <code>null</code> when the forwarded value is not a valid IP.</li>
<li><code>UserStorage::setNamespace()</code> now works when switching to another namespace after the storage has been used</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 23 Oct 2026 13:19:12 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/http/releases/tag/v3.3.5</guid>
	</item>
	<item>
		<title>Tester v2.6.3</title>
		<link>https://github.com/nette/tester/releases/tag/v2.6.3</link>
		<description>✨ New Features

Runner now warns you when Xdebug is active and slows the whole run down many times over, so a forgotten xdebug.mode no longer quietly costs you minutes (no warning when Xdebug serves as the code coverage engine)

🐛 Bug Fixes

FileMock is ready for PHP 8.6
Call arguments in stack traces stay on a single line even when strings contain newlines or tabs
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li>Runner now warns you when Xdebug is active and slows the whole run down many times over, so a forgotten <code>xdebug.mode</code> no longer quietly costs you minutes (no warning when Xdebug serves as the code coverage engine)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>FileMock</strong> is ready for PHP 8.6</li>
<li>Call arguments in stack traces stay on a single line even when strings contain newlines or tabs</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 23 Oct 2026 11:22:45 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tester/releases/tag/v2.6.3</guid>
	</item>
	<item>
		<title>Neon v3.4.9</title>
		<link>https://github.com/nette/neon/releases/tag/v3.4.9</link>
		<description>
PHP 8.6 is supported
A literal shaped like a date that is not a valid one, such as 2024-02-30 or 2024-13-01, now decodes as a plain string
The entity name !!chain is reserved for chained entities and can no longer be written in the input
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>PHP 8.6</strong> is supported</li>
<li>A literal shaped like a date that is not a valid one, such as <code>2024-02-30</code> or <code>2024-13-01</code>, now decodes as a plain string</li>
<li>The entity name <code>!!chain</code> is reserved for chained entities and can no longer be written in the input</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 22 Oct 2026 02:50:07 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/neon/releases/tag/v3.4.9</guid>
	</item>
	<item>
		<title>Security v3.2.7</title>
		<link>https://github.com/nette/security/releases/tag/v3.2.7</link>
		<description>✨ New Features

PHP 8.6 is now supported

🐛 Bug Fixes

The authenticator defined by security: users: in NEON is now autowired to services that require Nette\Security\Authenticator
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li><strong>PHP 8.6</strong> is now supported</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>The authenticator defined by <code>security: users:</code> in NEON is now autowired to services that require <code>Nette\Security\Authenticator</code></li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 22 Oct 2026 02:40:03 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/security/releases/tag/v3.2.7</guid>
	</item>
	<item>
		<title>Schema v1.4.0</title>
		<link>https://github.com/nette/schema/releases/tag/v1.4.0</link>
		<description>Your schema can now be the documentation of your configuration: give elements a
description, export the schema as JSON Schema, and editors offer completion, explain
each option and underline mistakes right in the config file.
✨ New Features

JsonSchema::export() – turns a schema into a JSON Schema
document, the format editors read to validate and complete JSON or YAML files. It exports
types, ranges, patterns, required items, enum values and descriptions. A type that exists
only in PHP, such as a class, throws NotSupportedException instead of exporting something
the schema would not accept.
description() – attach a human-readable description to any element. It does not affect
validation, and it travels into the JSON Schema export.
Expect::enum() – stop hand-rolling the conversion of backed enums:
Expect::enum(Suit::class) accepts the backing value or the case itself and always gives
you the case. An enum-typed property in Expect::from() maps to it automatically.
Expect::type(Suit::class) keeps meaning plain instanceof, as for any other class.
Expect::tuple() – a fixed-size list where each position has its own schema:
Expect::tuple([Expect::string(), Expect::int()]). otherItems() describes the rest
elements, extend() appends positions, and when configurations are layered, a later tuple
replaces the earlier one as a whole.
Expect::listOf() with wrap – Expect::listOf(&apos;string&apos;, wrap: true) also accepts a single
value and wraps it into a one-item list, so both email: foo@example.com and
email: [a@example.com, b@example.com] work.
mergeMode() and mergeWith() – say in the schema how layered configurations combine
instead of relying on the deep merge: Expect::arrayOf(&apos;string&apos;)-&gt;mergeMode(MergeMode::Replace)
takes the later array as a whole, while OverwriteKeys and AppendKeys merge by keys. Any
element can get its own combining function, such as
Expect::bool()-&gt;mergeWith(fn($value, $base) =&gt; $value || $base). A schema without them
merges exactly as before, and the same calls keep working in 2.0.
castTo(&apos;?type&apos;) – castTo(&apos;?string&apos;) keeps a null and casts everything else. A class
or an enum keeps the null even without the question mark, so
Expect::string()-&gt;nullable()-&gt;castTo(DateTime::class) just works.
Kind-specific element classes – Expect::string() returns a StringType, Expect::int()
a NumberType, Expect::listOf() an ArrayType, so your IDE and PHPStan know which options
each element has. They are subclasses of Type, so existing code keeps working.

⚠️ Deprecations

before() called repeatedly – a second before() on the same element still replaces the
first one, but raises a notice: in 2.0 the handlers will chain in declaration order. Merge
them into one.
&apos;?int[]&apos; – in 1.x it means an array of nullable items, while 2.0 reads it as a nullable
array, as phpDoc does. The notice names the replacement that keeps the meaning:
Expect::arrayOf(Expect::type(&apos;int&apos;)-&gt;nullable()).
Options that do not fit the element – min(), max(), pattern(), items() and
mergeDefaults() on a union such as Expect::type(&apos;int|string&apos;) belong to the variants:
Expect::anyOf(Expect::int()-&gt;min(1), Expect::string()-&gt;min(1)). Likewise pattern() on a
number or an array, items() on a string or a number and mergeDefaults() on anything but
an array raise a notice.

🐛 Bug Fixes

A nullable anyOf() containing a structure or an array gives null for a null input,
wherever the null sits among the variants.
Smaller fixes: anyOf()-&gt;deprecated() emits its warning, min() and max() keep the
precision of large integer bounds, and the internal _prevent_merging marker no longer
appears in the output of a structure.
</description>
		<content:encoded><![CDATA[
		<p>Your schema can now be the documentation of your configuration: give elements a<br>
description, export the schema as JSON Schema, and editors offer completion, explain<br>
each option and underline mistakes right in the config file.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>JsonSchema::export()</strong> – turns a schema into a <a href="https://json-schema.org" rel="nofollow">JSON Schema</a><br>
document, the format editors read to validate and complete JSON or YAML files. It exports<br>
types, ranges, patterns, required items, enum values and descriptions. A type that exists<br>
only in PHP, such as a class, throws <code>NotSupportedException</code> instead of exporting something<br>
the schema would not accept.</li>
<li><strong>description()</strong> – attach a human-readable description to any element. It does not affect<br>
validation, and it travels into the JSON Schema export.</li>
<li><strong>Expect::enum()</strong> – stop hand-rolling the conversion of backed enums:<br>
<code>Expect::enum(Suit::class)</code> accepts the backing value or the case itself and always gives<br>
you the case. An enum-typed property in <code>Expect::from()</code> maps to it automatically.<br>
<code>Expect::type(Suit::class)</code> keeps meaning plain <code>instanceof</code>, as for any other class.</li>
<li><strong>Expect::tuple()</strong> – a fixed-size list where each position has its own schema:<br>
<code>Expect::tuple([Expect::string(), Expect::int()])</code>. <code>otherItems()</code> describes the rest<br>
elements, <code>extend()</code> appends positions, and when configurations are layered, a later tuple<br>
replaces the earlier one as a whole.</li>
<li><strong>Expect::listOf() with wrap</strong> – <code>Expect::listOf('string', wrap: true)</code> also accepts a single<br>
value and wraps it into a one-item list, so both <code>email: foo@example.com</code> and<br>
<code>email: [a@example.com, b@example.com]</code> work.</li>
<li><strong>mergeMode() and mergeWith()</strong> – say in the schema how layered configurations combine<br>
instead of relying on the deep merge: <code>Expect::arrayOf('string')-&gt;mergeMode(MergeMode::Replace)</code><br>
takes the later array as a whole, while <code>OverwriteKeys</code> and <code>AppendKeys</code> merge by keys. Any<br>
element can get its own combining function, such as<br>
<code>Expect::bool()-&gt;mergeWith(fn($value, $base) =&gt; $value || $base)</code>. A schema without them<br>
merges exactly as before, and the same calls keep working in 2.0.</li>
<li><strong>castTo('?type')</strong> – <code>castTo('?string')</code> keeps a <code>null</code> and casts everything else. A class<br>
or an enum keeps the <code>null</code> even without the question mark, so<br>
<code>Expect::string()-&gt;nullable()-&gt;castTo(DateTime::class)</code> just works.</li>
<li><strong>Kind-specific element classes</strong> – <code>Expect::string()</code> returns a <code>StringType</code>, <code>Expect::int()</code><br>
a <code>NumberType</code>, <code>Expect::listOf()</code> an <code>ArrayType</code>, so your IDE and PHPStan know which options<br>
each element has. They are subclasses of <code>Type</code>, so existing code keeps working.</li>
</ul>
<h2><g-emoji class="g-emoji" alias="warning">⚠️</g-emoji> Deprecations</h2>
<ul>
<li><strong>before() called repeatedly</strong> – a second <code>before()</code> on the same element still replaces the<br>
first one, but raises a notice: in 2.0 the handlers will chain in declaration order. Merge<br>
them into one.</li>
<li><strong>'?int[]'</strong> – in 1.x it means an array of nullable items, while 2.0 reads it as a nullable<br>
array, as phpDoc does. The notice names the replacement that keeps the meaning:<br>
<code>Expect::arrayOf(Expect::type('int')-&gt;nullable())</code>.</li>
<li><strong>Options that do not fit the element</strong> – <code>min()</code>, <code>max()</code>, <code>pattern()</code>, <code>items()</code> and<br>
<code>mergeDefaults()</code> on a union such as <code>Expect::type('int|string')</code> belong to the variants:<br>
<code>Expect::anyOf(Expect::int()-&gt;min(1), Expect::string()-&gt;min(1))</code>. Likewise <code>pattern()</code> on a<br>
number or an array, <code>items()</code> on a string or a number and <code>mergeDefaults()</code> on anything but<br>
an array raise a notice.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>A nullable <code>anyOf()</code> containing a structure or an array gives <code>null</code> for a <code>null</code> input,<br>
wherever the <code>null</code> sits among the variants.</li>
<li>Smaller fixes: <code>anyOf()-&gt;deprecated()</code> emits its warning, <code>min()</code> and <code>max()</code> keep the<br>
precision of large integer bounds, and the internal <code>_prevent_merging</code> marker no longer<br>
appears in the output of a structure.</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 22 Oct 2026 02:22:13 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/schema/releases/tag/v1.4.0</guid>
	</item>
	<item>
		<title>Php Generator v4.2.3</title>
		<link>https://github.com/nette/php-generator/releases/tag/v4.2.3</link>
		<description>✨ New Features

PHP 8.6 is now supported

🐛 Bug Fixes

Loading a class with ClassType::from() or fromCode() now keeps the types of typed class constants (PHP 8.3)
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li><strong>PHP 8.6</strong> is now supported</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Loading a class with <code>ClassType::from()</code> or <code>fromCode()</code> now keeps the types of typed class constants (PHP 8.3)</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 22 Oct 2026 01:14:46 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/php-generator/releases/tag/v4.2.3</guid>
	</item>
	<item>
		<title>Latte v3.1.7</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.7</link>
		<description>💥 Breaking Changes

contenteditable, draggable, spellcheck, hidden are no longer treated as plain boolean attributes, because in HTML they are not. contenteditable={$editable} now renders contenteditable=&quot;true&quot; or contenteditable=&quot;false&quot;, so false really turns editing off instead of silently inheriting it from the parent, and draggable can be set to true at all. hidden and popover stay flags but keep a value, so hidden=&quot;until-found&quot; survives. With migration warnings on, Latte reports every place where the output changes; use |toggle to keep the old bare-name rendering
Sandbox – property names in a policy are case-sensitive, as they are in PHP: allowing visible no longer allows Visible
isPartialFunction() of the call nodes is renamed to isPartialApplication() – only matters for extensions working with the AST

✨ New Features

PHP 8.6 support
NodeHelpers::find() and findFirst() accept a node class as the filter: find($node, TextNode::class) returns a list&lt;TextNode&gt;, no type annotation needed
ExpressionNode::toValue() and hasValue() tell an extension whether an expression is a literal value and which; NodeHelpers::toValue() is deprecated in their favor

🔒 Security

The sandbox got a thorough review of its runtime checks: a dynamic property name is evaluated just once, so it cannot be checked with one value and accessed with another; (array) cast of an object is forbidden and foreach over an object checks its properties against the policy; $iterator no longer passes calls of unknown methods to the iterated object; and -&gt; / ?-&gt; method calls behave exactly as in PHP
A &lt;script&gt; whose type is anything the browser might execute (e.g. text/javascript1.5) is escaped as JavaScript; only a plain data type such as text/html or text/x-template is escaped as text
A custom sandbox policy without getCacheSignature() triggers a deprecation, because its instances with different rules would share compiled templates

🐛 Bug Fixes

{include parent} restores the block level after an exception and works in a block that includes itself
{capture $a[$i++]|filter} evaluates its target once
|slice with a negative start or length works on iterators the same way as on arrays, and |batch keeps every item of an iterator with repeated keys
An arrow function body swallows and, or and xor, as in PHP
The deprecation of an unqualified constant is no longer raised for class names written in capitals such as FOO::bar() or new FOO

🛡️ Robustness

Writing through ?-&gt; anywhere in a chain ($a?-&gt;b-&gt;c = 1) is a compile error instead of a PHP error later
The linter writes errors to stderr outside CLI too and restores its error handler for an unreadable file
</description>
		<content:encoded><![CDATA[
		<h2>💥 Breaking Changes</h2>
<ul>
<li><strong>contenteditable, draggable, spellcheck, hidden</strong> are no longer treated as plain boolean attributes, because in HTML they are not. <code>contenteditable={$editable}</code> now renders <code>contenteditable="true"</code> or <code>contenteditable="false"</code>, so <code>false</code> really turns editing off instead of silently inheriting it from the parent, and <code>draggable</code> can be set to <code>true</code> at all. <code>hidden</code> and <code>popover</code> stay flags but keep a value, so <code>hidden="until-found"</code> survives. With migration warnings on, Latte reports every place where the output changes; use <code>|toggle</code> to keep the old bare-name rendering</li>
<li><strong>Sandbox</strong> – property names in a policy are case-sensitive, as they are in PHP: allowing <code>visible</code> no longer allows <code>Visible</code></li>
<li><strong>isPartialFunction()</strong> of the call nodes is renamed to <strong>isPartialApplication()</strong> – only matters for extensions working with the AST</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li>PHP 8.6 support</li>
<li><strong>NodeHelpers::find()</strong> and <strong>findFirst()</strong> accept a node class as the filter: <code>find($node, TextNode::class)</code> returns a <code>list&lt;TextNode&gt;</code>, no type annotation needed</li>
<li><strong>ExpressionNode::toValue()</strong> and <strong>hasValue()</strong> tell an extension whether an expression is a literal value and which; <code>NodeHelpers::toValue()</code> is deprecated in their favor</li>
</ul>
<h2>🔒 Security</h2>
<ul>
<li>The sandbox got a thorough review of its runtime checks: a dynamic property name is evaluated just once, so it cannot be checked with one value and accessed with another; <code>(array)</code> cast of an object is forbidden and <code>foreach</code> over an object checks its properties against the policy; <code>$iterator</code> no longer passes calls of unknown methods to the iterated object; and <code>-&gt;</code> / <code>?-&gt;</code> method calls behave exactly as in PHP</li>
<li>A <code>&lt;script&gt;</code> whose <code>type</code> is anything the browser might execute (e.g. <code>text/javascript1.5</code>) is escaped as JavaScript; only a plain data type such as <code>text/html</code> or <code>text/x-template</code> is escaped as text</li>
<li>A custom sandbox policy without <code>getCacheSignature()</code> triggers a deprecation, because its instances with different rules would share compiled templates</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><code>{include parent}</code> restores the block level after an exception and works in a block that includes itself</li>
<li><code>{capture $a[$i++]|filter}</code> evaluates its target once</li>
<li><code>|slice</code> with a negative start or length works on iterators the same way as on arrays, and <code>|batch</code> keeps every item of an iterator with repeated keys</li>
<li>An arrow function body swallows <code>and</code>, <code>or</code> and <code>xor</code>, as in PHP</li>
<li>The deprecation of an unqualified constant is no longer raised for class names written in capitals such as <code>FOO::bar()</code> or <code>new FOO</code></li>
</ul>
<h2>🛡️ Robustness</h2>
<ul>
<li>Writing through <code>?-&gt;</code> anywhere in a chain (<code>$a?-&gt;b-&gt;c = 1</code>) is a compile error instead of a PHP error later</li>
<li>The linter writes errors to stderr outside CLI too and restores its error handler for an unreadable file</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 22 Oct 2026 00:11:30 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.7</guid>
	</item>
	<item>
		<title>Tracy v2.12.2</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.12.2</link>
		<description>
PHP 8.6 – Tracy is ready for the upcoming PHP version
BlueScreen – the markdown output (for agents and the .md files saved next to logged exceptions) now masks sensitive regions in source snippets just like the HTML page does, such as #[\SensitiveParameter] values in the compiled DI container (thx @spaze)
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>PHP 8.6</strong> – Tracy is ready for the upcoming PHP version</li>
<li><strong>BlueScreen</strong> – the markdown output (for agents and the <code>.md</code> files saved next to logged exceptions) now masks sensitive regions in source snippets just like the HTML page does, such as <code>#[\SensitiveParameter]</code> values in the compiled DI container (thx <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/spaze/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/spaze">@spaze</a>)</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 21 Oct 2026 23:25:00 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.12.2</guid>
	</item>
	<item>
		<title>Utils v4.0.11</title>
		<link>https://github.com/nette/utils/releases/tag/v4.0.11</link>
		<description>
PHP 8.6 is supported, so Nette Utils 4.0 now covers PHP 8.0 to 8.6
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>PHP 8.6</strong> is supported, so Nette Utils 4.0 now covers PHP 8.0 to 8.6</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 21 Oct 2026 16:53:25 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.0.11</guid>
	</item>
	<item>
		<title>Utils v4.1.6</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.6</link>
		<description>A small maintenance release: PHP 8.6 support and one fix for paths with a scheme.
✨ New Features

PHP 8.6 is supported

🐛 Bug Fixes

FileSystem::normalizePath(), joinPaths() and resolvePath() keep the scheme of paths like phar://
</description>
		<content:encoded><![CDATA[
		<p>A small maintenance release: PHP 8.6 support and one fix for paths with a scheme.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>PHP 8.6</strong> is supported</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>FileSystem::normalizePath()</strong>, <code>joinPaths()</code> and <code>resolvePath()</code> keep the scheme of paths like <code>phar://</code></li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 20 Oct 2026 17:48:48 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.6</guid>
	</item>
	<item>
		<title>Schema v1.3.7</title>
		<link>https://github.com/nette/schema/releases/tag/v1.3.7</link>
		<description>A polishing release that makes Schema more honest: mistakes in your schema now fail loudly instead of quietly rejecting or corrupting data, Expect::from() copes with more real-world classes, and PHP 8.6 is officially supported.
✨ New Features

PHP 8.6 is supported
Magic factories accept the default as a named argument, so Expect::string(default: &apos;abc&apos;) or Expect::int(default: 10) reads exactly as it means

🐛 Bug Fixes

A pattern that does not compile now throws InvalidStateException – previously every value failed as a mismatch next to a PHP warning, so a broken schema looked like invalid data
A transform calling process() on the same Processor no longer wipes out the outer run&apos;s errors, which could let invalid data through as valid
When a before() or transform() of a key schema turns the key into something other than int|string, you get a validation error instead of a TypeError or, worse, a silently cast key overwriting another item
Expect::from() reflects only public non-static properties of a class without a constructor, so a private, protected or static property no longer makes every process() crash on &quot;Cannot access private property&quot;
Expect::from() refuses a variadic constructor parameter with a clear exception instead of a cryptic ReflectionException
Warnings about an array key (e.g. a deprecated key) are labeled as a key, just like errors are
</description>
		<content:encoded><![CDATA[
		<p>A polishing release that makes Schema more honest: mistakes in your schema now fail loudly instead of quietly rejecting or corrupting data, <code>Expect::from()</code> copes with more real-world classes, and PHP 8.6 is officially supported.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>PHP 8.6</strong> is supported</li>
<li>Magic factories accept the default as a named argument, so <code>Expect::string(default: 'abc')</code> or <code>Expect::int(default: 10)</code> reads exactly as it means</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>A pattern that does not compile now throws <code>InvalidStateException</code> – previously every value failed as a mismatch next to a PHP warning, so a broken schema looked like invalid data</li>
<li>A transform calling <code>process()</code> on the same <code>Processor</code> no longer wipes out the outer run's errors, which could let invalid data through as valid</li>
<li>When a <code>before()</code> or <code>transform()</code> of a key schema turns the key into something other than <code>int|string</code>, you get a validation error instead of a <code>TypeError</code> or, worse, a silently cast key overwriting another item</li>
<li><strong>Expect::from()</strong> reflects only public non-static properties of a class without a constructor, so a private, protected or static property no longer makes every <code>process()</code> crash on "Cannot access private property"</li>
<li><strong>Expect::from()</strong> refuses a variadic constructor parameter with a clear exception instead of a cryptic <code>ReflectionException</code></li>
<li>Warnings about an array key (e.g. a deprecated key) are labeled as a key, just like errors are</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 20 Oct 2026 15:48:27 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/schema/releases/tag/v1.3.7</guid>
	</item>
	<item>
		<title>Tester v2.6.2</title>
		<link>https://github.com/nette/tester/releases/tag/v2.6.2</link>
		<description>A release about trust: a green result now means more. Assertions no longer skip checks silently, parallel runs clean up after themselves, reports stay valid whatever your tests print, and the code coverage report got a thorough round of fixes. And yes, PHP 8.6 is supported.
✨ New Features

TestCase::run() – no longer stops at the first failing method: every test method runs, results come first and the details of each failure follow (#469)
Stack traces show the actual call arguments, so you immediately see which call failed – redirect(&apos;https://…&apos;, 302) instead of a bare redirect()
PHP 8.6 support

🐛 Bug Fixes

Assert::exception() and Assert::error() – an empty or &apos;0&apos; message is now really checked instead of silently disabling the message check; pass null if you don&apos;t want to verify the message
@phpversion – boundaries and the == and != operators now work as documented: @phpVersion 8.4.3 runs on PHP 8.4.3, == 8.4.1 runs only on 8.4.1 and != 8.4.1 everywhere else. Common forms like @phpVersion 8.1 or &lt; 8.4 behave as before; == and != compare the full version, so == 8.4 matches no release
@multiple – 0 or a non-numeric value is reported as an error instead of quietly running the test twice
--stop-on-fail with parallel jobs no longer returns while other tests are still running; Ctrl+C terminates running test processes and every output handler is always finalized
Environment::lock() no longer eats into the test time limit while waiting for the lock on Windows
@httpcode reads the right status even when php-cgi prints a warning before the headers
Environment variables of the runner are restored after starting a test, and a Job works without a temp directory and keeps its stderr
Dumper no longer changes data reachable through references while dumping it; INF and NAN are dumped as valid PHP
HttpAssert – with follow: true the headers come from the final response only, so the Location of a redirect no longer leaks through; a header sent several times (e.g. Set-Cookie) is joined with a comma instead of keeping the last value; header existence checks count as assertions
Masks in Assert::match() – patterns with non-ASCII text match whole UTF-8 characters, %f% rejects invalid numbers like .1.2, and a failing regular expression no longer leaves pcre.backtrack_limit changed
FileMock – appending through several handles, modes like rb+ and touch() now behave like a real file
DomQuery – [attr$=&quot;value&quot;], attribute values containing quotes and selector lists like a, b on PHP &lt; 8.4 work correctly
JUnit report stays well-formed XML even when test output contains control characters or invalid UTF-8, and failed tests are counted in the failures attribute instead of errors (tools reading only errors now see 0)
Helpers::purge() refuses a path that resolves to the root directory, e.g. through .. or a symbolic link
Code coverage – the HTML report escapes file names, can be rendered repeatedly in one process, handles files with only dead code and numbers the last line of files without a trailing newline; Clover metrics include functions, enums and code outside classes; TAP or JUnit output on stdout is no longer polluted by the coverage summary, and tester exits with code 1 when the requested report cannot be generated
Clearer error messages, e.g. &quot;No assertions were executed in this test.&quot; instead of &quot;This test forgets to execute an assertion.&quot;, and Assert::contains() keeps your custom description
</description>
		<content:encoded><![CDATA[
		<p>A release about trust: a green result now means more. Assertions no longer skip checks silently, parallel runs clean up after themselves, reports stay valid whatever your tests print, and the code coverage report got a thorough round of fixes. And yes, PHP 8.6 is supported.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>TestCase::run()</strong> – no longer stops at the first failing method: every test method runs, results come first and the details of each failure follow (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4459033444" data-permission-text="Title is private" data-url="https://github.com/nette/tester/issues/469" data-hovercard-type="issue" data-hovercard-url="/nette/tester/issues/469/hovercard" href="https://github.com/nette/tester/issues/469">#469</a>)</li>
<li>Stack traces show the actual call arguments, so you immediately see which call failed – <code>redirect('https://…', 302)</code> instead of a bare <code>redirect()</code></li>
<li>PHP 8.6 support</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Assert::exception()</strong> and <strong>Assert::error()</strong> – an empty or <code>'0'</code> message is now really checked instead of silently disabling the message check; pass <code>null</code> if you don't want to verify the message</li>
<li><strong><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/phpversion/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/phpversion">@phpversion</a></strong> – boundaries and the <code>==</code> and <code>!=</code> operators now work as documented: <code>@phpVersion 8.4.3</code> runs on PHP 8.4.3, <code>== 8.4.1</code> runs only on 8.4.1 and <code>!= 8.4.1</code> everywhere else. Common forms like <code>@phpVersion 8.1</code> or <code>&lt; 8.4</code> behave as before; <code>==</code> and <code>!=</code> compare the full version, so <code>== 8.4</code> matches no release</li>
<li><strong><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/multiple/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/multiple">@multiple</a></strong> – <code>0</code> or a non-numeric value is reported as an error instead of quietly running the test twice</li>
<li><strong>--stop-on-fail</strong> with parallel jobs no longer returns while other tests are still running; Ctrl+C terminates running test processes and every output handler is always finalized</li>
<li><strong>Environment::lock()</strong> no longer eats into the test time limit while waiting for the lock on Windows</li>
<li><strong><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/httpcode/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/httpcode">@httpcode</a></strong> reads the right status even when php-cgi prints a warning before the headers</li>
<li>Environment variables of the runner are restored after starting a test, and a <strong>Job</strong> works without a temp directory and keeps its stderr</li>
<li><strong>Dumper</strong> no longer changes data reachable through references while dumping it; <code>INF</code> and <code>NAN</code> are dumped as valid PHP</li>
<li><strong>HttpAssert</strong> – with <code>follow: true</code> the headers come from the final response only, so the <code>Location</code> of a redirect no longer leaks through; a header sent several times (e.g. <code>Set-Cookie</code>) is joined with a comma instead of keeping the last value; header existence checks count as assertions</li>
<li>Masks in <strong>Assert::match()</strong> – patterns with non-ASCII text match whole UTF-8 characters, <code>%f%</code> rejects invalid numbers like <code>.1.2</code>, and a failing regular expression no longer leaves <code>pcre.backtrack_limit</code> changed</li>
<li><strong>FileMock</strong> – appending through several handles, modes like <code>rb+</code> and <code>touch()</code> now behave like a real file</li>
<li><strong>DomQuery</strong> – <code>[attr$="value"]</code>, attribute values containing quotes and selector lists like <code>a, b</code> on PHP &lt; 8.4 work correctly</li>
<li><strong>JUnit</strong> report stays well-formed XML even when test output contains control characters or invalid UTF-8, and failed tests are counted in the <code>failures</code> attribute instead of <code>errors</code> (tools reading only <code>errors</code> now see <code>0</code>)</li>
<li><strong>Helpers::purge()</strong> refuses a path that resolves to the root directory, e.g. through <code>..</code> or a symbolic link</li>
<li>Code coverage – the HTML report escapes file names, can be rendered repeatedly in one process, handles files with only dead code and numbers the last line of files without a trailing newline; Clover metrics include functions, enums and code outside classes; TAP or JUnit output on stdout is no longer polluted by the coverage summary, and <code>tester</code> exits with code 1 when the requested report cannot be generated</li>
<li>Clearer error messages, e.g. "No assertions were executed in this test." instead of "This test forgets to execute an assertion.", and <strong>Assert::contains()</strong> keeps your custom description</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 13 Sep 2026 00:22:52 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tester/releases/tag/v2.6.2</guid>
	</item>
	<item>
		<title>Http v3.4.1</title>
		<link>https://github.com/nette/http/releases/tag/v3.4.1</link>
		<description>This release hardens the reverse-proxy trust model: the real client address, scheme and host are now resolved correctly from multi-hop Forwarded and X-Forwarded-* headers, and you can choose which of them your proxy is allowed to speak for. On top of that, CLI scripts finally get a meaningful request URL.
💥 Breaking Changes

Applications configured through the DI extension now trust only X-Forwarded-* headers from a trusted proxy by default, so a client-supplied Forwarded header can no longer spoof the address or host. If your proxy uses the Forwarded header, set http: proxyHeaders: forwarded (or both).
getRemoteAddress() returns null instead of a non-IP string when the innermost forwarded value is not a valid IP address (e.g. an obfuscated identifier or a broken chain).

✨ New Features

proxyHeaders option (both|xForwarded|forwarded|none) and the $forwarded / $xForwarded flags of RequestFactory::setProxy() let you tell Nette exactly which forwarding headers your proxy manages – and ignore the rest.
RequestFactory::setBaseUrl() and the http: baseUrl option give CLI runs (cron, tasks, MCP servers) a real request URL, so %baseUrl%, LinkGenerator, template $baseUrl and assets work outside the web server too. It kicks in only when no host can be detected, so web requests are unaffected.

🐛 Bug Fixes

Trusted-proxy resolution now parses Forwarded into proper RFC 7239 hops and picks the client by stripping trailing trusted proxies, instead of blindly trusting the leftmost, client-spoofable value; scheme and host are taken from the same hop as the selected address and no longer discarded on multi-hop headers.
Response::setCookie() treats an explicitly empty $path or $domain as given: &apos;&apos; now yields a host-only cookie or the / path instead of silently falling back to the configured defaults. Only null means &quot;not specified&quot;.
</description>
		<content:encoded><![CDATA[
		<p>This release hardens the reverse-proxy trust model: the real client address, scheme and host are now resolved correctly from multi-hop <code>Forwarded</code> and <code>X-Forwarded-*</code> headers, and you can choose which of them your proxy is allowed to speak for. On top of that, CLI scripts finally get a meaningful request URL.</p>
<h2>💥 Breaking Changes</h2>
<ul>
<li>Applications configured through the DI extension now trust <strong>only <code>X-Forwarded-*</code></strong> headers from a trusted proxy by default, so a client-supplied <code>Forwarded</code> header can no longer spoof the address or host. If your proxy uses the <code>Forwarded</code> header, set <code>http: proxyHeaders: forwarded</code> (or <code>both</code>).</li>
<li><strong>getRemoteAddress()</strong> returns <code>null</code> instead of a non-IP string when the innermost forwarded value is not a valid IP address (e.g. an obfuscated identifier or a broken chain).</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong>proxyHeaders</strong> option (<code>both|xForwarded|forwarded|none</code>) and the <code>$forwarded</code> / <code>$xForwarded</code> flags of <strong>RequestFactory::setProxy()</strong> let you tell Nette exactly which forwarding headers your proxy manages – and ignore the rest.</li>
<li><strong>RequestFactory::setBaseUrl()</strong> and the <code>http: baseUrl</code> option give CLI runs (cron, tasks, MCP servers) a real request URL, so <code>%baseUrl%</code>, LinkGenerator, template <code>$baseUrl</code> and assets work outside the web server too. It kicks in only when no host can be detected, so web requests are unaffected.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Trusted-proxy resolution now parses <code>Forwarded</code> into proper RFC 7239 hops and picks the client by stripping trailing trusted proxies, instead of blindly trusting the leftmost, client-spoofable value; scheme and host are taken from the same hop as the selected address and no longer discarded on multi-hop headers.</li>
<li><strong>Response::setCookie()</strong> treats an explicitly empty <code>$path</code> or <code>$domain</code> as given: <code>''</code> now yields a host-only cookie or the <code>/</code> path instead of silently falling back to the configured defaults. Only <code>null</code> means "not specified".</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 27 Aug 2026 04:25:18 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/http/releases/tag/v3.4.1</guid>
	</item>
	<item>
		<title>Di v3.2.7</title>
		<link>https://github.com/nette/di/releases/tag/v3.2.7</link>
		<description>The container stops being a black box. This release adds a first-class introspection API, a PSR-11 bridge, and – finally – containers that actually reload themselves in long-running processes instead of silently serving a stale build forever. A handful of quiet misconfigurations were also promoted to loud errors.
✨ New Features

Containers now reload themselves. PHP cannot redeclare a loaded class, so a worker, dev server or any long-running process with auto-rebuild kept serving the very first compiled container even after the configs changed and the file on disk was regenerated. Each build now declares a fresh class and the loader decides by file content, so a rebuild triggered by another process over the same cache is picked up too.
New Container::getServiceDescriptors() – a read-only snapshot of every registered service (name, type, autowiring, tags, aliases, and the instance if it exists), in definition order, without instantiating anything. Tools that until now read the container&apos;s private properties through Closure::bind() and scanned createService* methods by reflection can drop the tricks; the Tracy panel already has.
New Nette\Bridges\DIPsr\PsrContainer – wrap your container and hand it to any library that speaks PSR-11. get() resolves both service names and autowired types, with ambiguity reported rather than guessed.
A service produced by a factory can autowire itself in its own setup, so @self and self-typed arguments work there like anywhere else.

🐛 Bug Fixes

Windows users: writing the compiled container no longer fails intermittently with &quot;Access is denied&quot; when antivirus or an opcache handle holds the target file for a moment – the rename is briefly retried, and the opcache handle is dropped first. Other platforms behave exactly as before.
addService() refuses a name already taken by a factory, matching the existing behavior for instances. The counterpart: removeService() now removes factories too, so a name freed by removeService() is genuinely free.

⚡ Performance

Registering a definition no longer scans every existing definition to check for a case-insensitive name clash; an index does it in constant time. Containers with thousands of services notice.
</description>
		<content:encoded><![CDATA[
		<p>The container stops being a black box. This release adds a first-class introspection API, a PSR-11 bridge, and – finally – containers that actually reload themselves in long-running processes instead of silently serving a stale build forever. A handful of quiet misconfigurations were also promoted to loud errors.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>Containers now reload themselves.</strong> PHP cannot redeclare a loaded class, so a worker, dev server or any long-running process with auto-rebuild kept serving the very first compiled container even after the configs changed and the file on disk was regenerated. Each build now declares a fresh class and the loader decides by file <em>content</em>, so a rebuild triggered by another process over the same cache is picked up too.</li>
<li><strong>New <code>Container::getServiceDescriptors()</code></strong> – a read-only snapshot of every registered service (name, type, autowiring, tags, aliases, and the instance if it exists), in definition order, without instantiating anything. Tools that until now read the container's private properties through <code>Closure::bind()</code> and scanned <code>createService*</code> methods by reflection can drop the tricks; the Tracy panel already has.</li>
<li><strong>New <code>Nette\Bridges\DIPsr\PsrContainer</code></strong> – wrap your container and hand it to any library that speaks PSR-11. <code>get()</code> resolves both service names and autowired types, with ambiguity reported rather than guessed.</li>
<li><strong>A service produced by a factory can autowire itself in its own <code>setup</code></strong>, so <code>@self</code> and self-typed arguments work there like anywhere else.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Windows users: writing the compiled container no longer fails intermittently with "Access is denied" when antivirus or an opcache handle holds the target file for a moment – the rename is briefly retried, and the opcache handle is dropped first. Other platforms behave exactly as before.</li>
<li><code>addService()</code> refuses a name already taken by a factory, matching the existing behavior for instances. The counterpart: <strong><code>removeService()</code> now removes factories too</strong>, so a name freed by <code>removeService()</code> is genuinely free.</li>
</ul>
<h2>⚡ Performance</h2>
<ul>
<li>Registering a definition no longer scans every existing definition to check for a case-insensitive name clash; an index does it in constant time. Containers with thousands of services notice.</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 27 Aug 2026 01:17:30 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/di/releases/tag/v3.2.7</guid>
	</item>
	<item>
		<title>Tracy v2.12.1</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.12.1</link>
		<description>A hardening release that follows 2.12.0. The Dumper learns to speak modern PHP – virtual hooked properties, WeakReference, PHP 8.5 URI objects – any HTTP client can now ask for markdown output with a single header, and a long list of fixes makes the Bar, the session and the logger behave under concurrency, broken storage and hostile input.
✨ New Features

The Dumper now understands modern PHP constructs – PHP 8.4 virtual hooked properties render as {virtual} instead of the misleading unset, WeakReference shows its target (or (dead)), PHP 8.5 Uri\Rfc3986\Uri and Uri\WhatWg\Url expand into address and components, closures reveal the class of their bound $this, and lazy objects expose their eagerly-initialized private and protected properties without throwing
cURL handles are dumped again – now via CurlHandle, not the long-gone resource type
X-Tracy-Agent request header – non-browser agents (curl, HTTP clients, CI jobs) can ask for markdown output without the webdriver cookie, and a non-HTML response carries the markdown BlueScreen straight in the body
editor: false in the Nette configuration finally disables editor links; previously the value was silently ignored

🐛 Bug Fixes

Tracy&apos;s fetch() wrapper no longer drops the options argument and no longer mutates the caller&apos;s Request object – AJAX calls reach the server exactly as your code wrote them
The XMLHttpRequest patch stopped stacking a load listener on every open() call, and a dump with a broken payload no longer aborts the initialization of every other dump on the page
A corrupt localStorage / sessionStorage entry no longer breaks the Bar and Toggle initialization
Toggle links can be activated from the keyboard again
Dumper::$keysToHide and the scrubber now also apply to properties returned by __debugInfo() and custom object exporters – sensitive values no longer slip through
Debugger::dump() with return: true respects $keysToHide and passes the options in CLI mode
The email throttle is now atomic and honest: an invalid $emailSnooze interval throws instead of silently flooding your inbox, concurrent requests can no longer both send the same notification, and the snooze window restarts only after the mail was really sent
TracyToPsrLoggerAdapter no longer logs an exception twice when the accompanying message adds no information, and casts Stringable messages to string
FileSession hardening – session files are created with mode 0600, unserialization refuses objects, the cookie gets SameSite=Lax plus the secure flag on HTTPS, and concurrent garbage collection no longer emits warnings
BlueScreen no longer triggers autoloading of class names it finds in an exception message
The exception fallback output is HTML-escaped in HTML mode
A repeated DeferredContent::enable() after output has started is a harmless no-op instead of an exception
The Dumper&apos;s exposer ordering comparator is a valid total order and understands interface-keyed exposers, so custom exposers are picked deterministically
Removed legacy browser workarounds (IE getAttribute flag, keyCode, navigator.platform, document.write() in the panel popup) and evalScripts() no longer leaves executed &lt;script&gt; clones behind in the DOM
</description>
		<content:encoded><![CDATA[
		<p>A hardening release that follows 2.12.0. The Dumper learns to speak modern PHP – virtual hooked properties, <code>WeakReference</code>, PHP 8.5 URI objects – any HTTP client can now ask for markdown output with a single header, and a long list of fixes makes the Bar, the session and the logger behave under concurrency, broken storage and hostile input.</p>
<h2>✨ New Features</h2>
<ul>
<li>The Dumper now understands modern PHP constructs – PHP 8.4 virtual hooked properties render as <code>{virtual}</code> instead of the misleading <code>unset</code>, <code>WeakReference</code> shows its target (or <code>(dead)</code>), PHP 8.5 <code>Uri\Rfc3986\Uri</code> and <code>Uri\WhatWg\Url</code> expand into address and components, closures reveal the class of their bound <code>$this</code>, and lazy objects expose their eagerly-initialized private and protected properties without throwing</li>
<li>cURL handles are dumped again – now via <code>CurlHandle</code>, not the long-gone resource type</li>
<li><strong>X-Tracy-Agent</strong> request header – non-browser agents (curl, HTTP clients, CI jobs) can ask for markdown output without the webdriver cookie, and a non-HTML response carries the markdown BlueScreen straight in the body</li>
<li><strong><code>editor: false</code></strong> in the Nette configuration finally disables editor links; previously the value was silently ignored</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>Tracy's <code>fetch()</code> wrapper no longer drops the options argument and no longer mutates the caller's <code>Request</code> object – AJAX calls reach the server exactly as your code wrote them</li>
<li>The <code>XMLHttpRequest</code> patch stopped stacking a load listener on every <code>open()</code> call, and a dump with a broken payload no longer aborts the initialization of every other dump on the page</li>
<li>A corrupt <code>localStorage</code> / <code>sessionStorage</code> entry no longer breaks the Bar and Toggle initialization</li>
<li>Toggle links can be activated from the keyboard again</li>
<li><code>Dumper::$keysToHide</code> and the scrubber now also apply to properties returned by <code>__debugInfo()</code> and custom object exporters – sensitive values no longer slip through</li>
<li><code>Debugger::dump()</code> with <code>return: true</code> respects <code>$keysToHide</code> and passes the options in CLI mode</li>
<li>The email throttle is now atomic and honest: an invalid <code>$emailSnooze</code> interval throws instead of silently flooding your inbox, concurrent requests can no longer both send the same notification, and the snooze window restarts only after the mail was really sent</li>
<li><code>TracyToPsrLoggerAdapter</code> no longer logs an exception twice when the accompanying message adds no information, and casts <code>Stringable</code> messages to string</li>
<li><code>FileSession</code> hardening – session files are created with mode 0600, unserialization refuses objects, the cookie gets <code>SameSite=Lax</code> plus the <code>secure</code> flag on HTTPS, and concurrent garbage collection no longer emits warnings</li>
<li>BlueScreen no longer triggers autoloading of class names it finds in an exception message</li>
<li>The exception fallback output is HTML-escaped in HTML mode</li>
<li>A repeated <code>DeferredContent::enable()</code> after output has started is a harmless no-op instead of an exception</li>
<li>The Dumper's exposer ordering comparator is a valid total order and understands interface-keyed exposers, so custom exposers are picked deterministically</li>
<li>Removed legacy browser workarounds (IE <code>getAttribute</code> flag, <code>keyCode</code>, <code>navigator.platform</code>, <code>document.write()</code> in the panel popup) and <code>evalScripts()</code> no longer leaves executed <code>&lt;script&gt;</code> clones behind in the DOM</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 18 Aug 2026 11:06:27 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.12.1</guid>
	</item>
	<item>
		<title>Robot Loader v4.1.3</title>
		<link>https://github.com/nette/robot-loader/releases/tag/v4.1.3</link>
		<description>
setCacheDirectory() replaces setTempDirectory(), matching the naming used in Latte. The old method still works as a deprecated alias, so there is no rush to change anything.
Writing the cache on Windows no longer fails randomly with &quot;Access is denied&quot;. An antivirus scanning the freshly written file could hold it open just long enough to break the rename(); the write is now retried briefly before giving up. Other platforms behave exactly as before.
When the cache file cannot be written, the exception now tells you why instead of just naming the file.
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>setCacheDirectory()</strong> replaces <code>setTempDirectory()</code>, matching the naming used in Latte. The old method still works as a deprecated alias, so there is no rush to change anything.</li>
<li>Writing the cache on Windows no longer fails randomly with "Access is denied". An antivirus scanning the freshly written file could hold it open just long enough to break the <code>rename()</code>; the write is now retried briefly before giving up. Other platforms behave exactly as before.</li>
<li>When the cache file cannot be written, the exception now tells you <em>why</em> instead of just naming the file.</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 18 Aug 2026 10:26:19 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/robot-loader/releases/tag/v4.1.3</guid>
	</item>
	<item>
		<title>Schema v1.3.6</title>
		<link>https://github.com/nette/schema/releases/tag/v1.3.6</link>
		<description>A round of fixes to the corners of the validation pipeline that only bite once your schema gets interesting: nullable arrays, invalid keys, deprecated items and anyOf() branches. On top of that, castTo() now speaks backed enums.
✨ New Features

castTo() now accepts a backed enum – Expect::string()-&gt;castTo(Status::class) converts the value via Status::from() and, when it doesn&apos;t match, reports a proper validation error listing all allowed cases instead of blowing up with a ValueError. Pure (non-backed) enums are rejected up front with a clear message.
Casting to a class that can&apos;t swallow the given value no longer surfaces as a bare Error – you get an InvalidStateException naming the target class, so you know what failed to be constructed.

🐛 Bug Fixes

A null value for a nullable array is finally left as null. Previously the &quot;NEON can&apos;t tell null from an empty array&quot; workaround kicked in even for schemas explicitly declared nullable(), silently turning your null into [].
Items with an invalid key are now dropped instead of being merged together – all failing keys used to collapse into a single &apos;&apos; entry, quietly overwriting each other&apos;s values.
Processor::getWarnings() no longer dies with an error when called before anything was processed; it simply returns an empty array.
deprecated() on a required structure no longer emits a warning when the item isn&apos;t present in the input at all – you only get warned about deprecated items you actually used.
anyOf() stopped losing information in the winning branch: dynamic parameters found inside are propagated to the outer context again (they used to be silently forgotten, so DI never validated them), and skipDefaults is now honored inside the branch. A DynamicParameter schema also no longer registers itself for deferred validation.
Error messages keep unknown %placeholders% intact instead of tripping over an undefined index.
</description>
		<content:encoded><![CDATA[
		<p>A round of fixes to the corners of the validation pipeline that only bite once your schema gets interesting: nullable arrays, invalid keys, deprecated items and <code>anyOf()</code> branches. On top of that, <code>castTo()</code> now speaks backed enums.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>castTo()</strong> now accepts a backed enum – <code>Expect::string()-&gt;castTo(Status::class)</code> converts the value via <code>Status::from()</code> and, when it doesn't match, reports a proper validation error listing all allowed cases instead of blowing up with a <code>ValueError</code>. Pure (non-backed) enums are rejected up front with a clear message.</li>
<li>Casting to a class that can't swallow the given value no longer surfaces as a bare <code>Error</code> – you get an <strong>InvalidStateException</strong> naming the target class, so you know <em>what</em> failed to be constructed.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>A <code>null</code> value for a nullable array is finally left as <code>null</code>. Previously the "NEON can't tell <code>null</code> from an empty array" workaround kicked in even for schemas explicitly declared <code>nullable()</code>, silently turning your <code>null</code> into <code>[]</code>.</li>
<li>Items with an invalid key are now dropped instead of being merged together – all failing keys used to collapse into a single <code>''</code> entry, quietly overwriting each other's values.</li>
<li><strong>Processor::getWarnings()</strong> no longer dies with an error when called before anything was processed; it simply returns an empty array.</li>
<li><code>deprecated()</code> on a required structure no longer emits a warning when the item isn't present in the input at all – you only get warned about deprecated items you actually used.</li>
<li><strong>anyOf()</strong> stopped losing information in the winning branch: dynamic parameters found inside are propagated to the outer context again (they used to be silently forgotten, so DI never validated them), and <code>skipDefaults</code> is now honored inside the branch. A <code>DynamicParameter</code> schema also no longer registers itself for deferred validation.</li>
<li>Error messages keep unknown <code>%placeholders%</code> intact instead of tripping over an undefined index.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 17 Aug 2026 18:17:51 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/schema/releases/tag/v1.3.6</guid>
	</item>
	<item>
		<title>Routing v3.1.4</title>
		<link>https://github.com/nette/routing/releases/tag/v3.1.4</link>
		<description>
Double quotes in URL path segments are now percent-encoded as RFC 3986 requires. Previously an unencoded &quot; in a generated URL could break out of an HTML attribute in output contexts that are not HTML-escaped.
Host wildcards (%tld%, %domain%, %sld%) no longer mangle IP addresses: IPv6 hosts like [::1] and the address 0.0.0.0 were mistakenly split on dots as if they were domain names. Routes with host masks now work correctly when the site is accessed via an IP address.
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Double quotes in URL path segments are now percent-encoded as RFC 3986 requires. Previously an unencoded <code>"</code> in a generated URL could break out of an HTML attribute in output contexts that are not HTML-escaped.</li>
<li>Host wildcards (<code>%tld%</code>, <code>%domain%</code>, <code>%sld%</code>) no longer mangle IP addresses: IPv6 hosts like <code>[::1]</code> and the address <code>0.0.0.0</code> were mistakenly split on dots as if they were domain names. Routes with host masks now work correctly when the site is accessed via an IP address.</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 09 Aug 2026 14:03:45 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/routing/releases/tag/v3.1.4</guid>
	</item>
	<item>
		<title>Mail v4.1.3</title>
		<link>https://github.com/nette/mail/releases/tag/v4.1.3</link>
		<description>This release teaches SmtpMailer to speak OAuth, DkimSigner to sign with Ed25519, and CssInliner to resolve styles the way a browser does. Add a DKIM security fix and the deliverability headers Gmail and Yahoo now demand, and there is a good reason to upgrade even if you never hit any of the fixed bugs.
🔒 Security

DkimSigner no longer emits the l= body-length tag. With it, anyone could append arbitrary content to a signed message without invalidating the signature.

✨ New Features

SmtpMailer::setAccessToken() – authenticates with an OAuth 2.0 access token (XOAUTH2), which Gmail and Microsoft 365 require now that they are retiring passwords for SMTP. Pass the token as a string, or as a callback that is called on each connection so an expiring token gets refreshed.
Message::setUnsubscribe() – emits the pair of one-click unsubscribe headers (RFC 8058) that Gmail and Yahoo require from bulk senders. Getting the two headers to agree is exactly the kind of detail that is easy to get wrong by hand; the headers are also DKIM-signed, so the unsubscribe target cannot be swapped in transit.
DkimSigner signs with Ed25519 keys (RFC 8463). The algorithm is detected from the key itself, so no new argument is needed. New header oversigning (opt-in via $oversignHeaders) makes appending a second From: header break the signature.
FileMailer – a mailer that writes each message to an .eml file instead of sending it; ideal for development and testing.
Addresses with internationalized domains – jan@příklad.cz – are converted to punycode automatically, so they work with ordinary SMTP servers instead of failing with a puzzling server error.

🐛 Bug Fixes

CssInliner resolves competing declarations by the real CSS cascade – !important, inline styles, selector specificity, source order – instead of letting the last rule win. Inlined emails now look like the page the stylesheet was written for, and each property is written out once, with the winning value.
CssInliner no longer turns width: auto or calc(...) into width=&quot;0&quot; (which collapsed the cell in Outlook), and treats property names case-insensitively, as CSS does.
Header names are case-insensitive per RFC 5322: getHeader(&apos;from&apos;) finds the From header, setHeader(&apos;SUBJECT&apos;) replaces the existing Subject instead of adding a second one, and DKIM signing matches headers whatever their spelling.
SmtpMailer got a robustness overhaul: a persistent connection dropped by an idle server is detected and re-established instead of failing every send from then on; large messages are no longer silently truncated when the socket buffer fills up; the read timeout holds even against a server that never stops talking; and authentication picks only from mechanisms the server actually offers, including the legacy AUTH= advertisement.
SmtpMailer STARTTLS accepts only TLS 1.2 and 1.3, reports the actual handshake failure reason instead of a bare &quot;Unable to connect&quot;, and defaults to the submission port 587.
FallbackMailer no longer keeps retrying a mailer whose failure is permanent, like rejected credentials – retrying cannot fix those.
DkimSigner relaxed canonicalization collapses every whitespace sequence, including tabs, so signatures on such headers verify everywhere.
</description>
		<content:encoded><![CDATA[
		<p>This release teaches SmtpMailer to speak OAuth, DkimSigner to sign with Ed25519, and CssInliner to resolve styles the way a browser does. Add a DKIM security fix and the deliverability headers Gmail and Yahoo now demand, and there is a good reason to upgrade even if you never hit any of the fixed bugs.</p>
<h2>🔒 Security</h2>
<ul>
<li><strong>DkimSigner</strong> no longer emits the <code>l=</code> body-length tag. With it, anyone could append arbitrary content to a signed message without invalidating the signature.</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong>SmtpMailer::setAccessToken()</strong> – authenticates with an OAuth 2.0 access token (XOAUTH2), which Gmail and Microsoft 365 require now that they are retiring passwords for SMTP. Pass the token as a string, or as a callback that is called on each connection so an expiring token gets refreshed.</li>
<li><strong>Message::setUnsubscribe()</strong> – emits the pair of one-click unsubscribe headers (RFC 8058) that Gmail and Yahoo require from bulk senders. Getting the two headers to agree is exactly the kind of detail that is easy to get wrong by hand; the headers are also DKIM-signed, so the unsubscribe target cannot be swapped in transit.</li>
<li><strong>DkimSigner</strong> signs with Ed25519 keys (RFC 8463). The algorithm is detected from the key itself, so no new argument is needed. New header oversigning (opt-in via <code>$oversignHeaders</code>) makes appending a second <code>From:</code> header break the signature.</li>
<li><strong>FileMailer</strong> – a mailer that writes each message to an <code>.eml</code> file instead of sending it; ideal for development and testing.</li>
<li>Addresses with internationalized domains – jan@příklad.cz – are converted to punycode automatically, so they work with ordinary SMTP servers instead of failing with a puzzling server error.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>CssInliner</strong> resolves competing declarations by the real CSS cascade – <code>!important</code>, inline styles, selector specificity, source order – instead of letting the last rule win. Inlined emails now look like the page the stylesheet was written for, and each property is written out once, with the winning value.</li>
<li><strong>CssInliner</strong> no longer turns <code>width: auto</code> or <code>calc(...)</code> into <code>width="0"</code> (which collapsed the cell in Outlook), and treats property names case-insensitively, as CSS does.</li>
<li>Header names are case-insensitive per RFC 5322: <code>getHeader('from')</code> finds the <code>From</code> header, <code>setHeader('SUBJECT')</code> replaces the existing Subject instead of adding a second one, and DKIM signing matches headers whatever their spelling.</li>
<li><strong>SmtpMailer</strong> got a robustness overhaul: a persistent connection dropped by an idle server is detected and re-established instead of failing every send from then on; large messages are no longer silently truncated when the socket buffer fills up; the read timeout holds even against a server that never stops talking; and authentication picks only from mechanisms the server actually offers, including the legacy <code>AUTH=</code> advertisement.</li>
<li><strong>SmtpMailer</strong> STARTTLS accepts only TLS 1.2 and 1.3, reports the actual handshake failure reason instead of a bare "Unable to connect", and defaults to the submission port 587.</li>
<li><strong>FallbackMailer</strong> no longer keeps retrying a mailer whose failure is permanent, like rejected credentials – retrying cannot fix those.</li>
<li><strong>DkimSigner</strong> relaxed canonicalization collapses every whitespace sequence, including tabs, so signatures on such headers verify everywhere.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 27 Jul 2026 15:39:36 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/mail/releases/tag/v4.1.3</guid>
	</item>
	<item>
		<title>Mail v4.1.3</title>
		<link>https://github.com/nette/mail/releases/tag/untagged-eba1b214f5c37cb81cd9</link>
		<description>This release teaches SmtpMailer to speak OAuth, DkimSigner to sign with Ed25519, and CssInliner to resolve styles the way a browser does. Add a DKIM security fix and the deliverability headers Gmail and Yahoo now demand, and there is a good reason to upgrade even if you never hit any of the fixed bugs.
🔒 Security

DkimSigner no longer emits the l= body-length tag. With it, anyone could append arbitrary content to a signed message without invalidating the signature.

✨ New Features

SmtpMailer::setAccessToken() – authenticates with an OAuth 2.0 access token (XOAUTH2), which Gmail and Microsoft 365 require now that they are retiring passwords for SMTP. Pass the token as a string, or as a callback that is called on each connection so an expiring token gets refreshed.
Message::setUnsubscribe() – emits the pair of one-click unsubscribe headers (RFC 8058) that Gmail and Yahoo require from bulk senders. Getting the two headers to agree is exactly the kind of detail that is easy to get wrong by hand; the headers are also DKIM-signed, so the unsubscribe target cannot be swapped in transit.
DkimSigner signs with Ed25519 keys (RFC 8463). The algorithm is detected from the key itself, so no new argument is needed. New header oversigning (opt-in via $oversignHeaders) makes appending a second From: header break the signature.
FileMailer – a mailer that writes each message to an .eml file instead of sending it; ideal for development and testing.
Addresses with internationalized domains – jan@příklad.cz – are converted to punycode automatically, so they work with ordinary SMTP servers instead of failing with a puzzling server error.

🐛 Bug Fixes

CssInliner resolves competing declarations by the real CSS cascade – !important, inline styles, selector specificity, source order – instead of letting the last rule win. Inlined emails now look like the page the stylesheet was written for, and each property is written out once, with the winning value.
CssInliner no longer turns width: auto or calc(...) into width=&quot;0&quot; (which collapsed the cell in Outlook), and treats property names case-insensitively, as CSS does.
Header names are case-insensitive per RFC 5322: getHeader(&apos;from&apos;) finds the From header, setHeader(&apos;SUBJECT&apos;) replaces the existing Subject instead of adding a second one, and DKIM signing matches headers whatever their spelling.
SmtpMailer got a robustness overhaul: a persistent connection dropped by an idle server is detected and re-established instead of failing every send from then on; large messages are no longer silently truncated when the socket buffer fills up; the read timeout holds even against a server that never stops talking; and authentication picks only from mechanisms the server actually offers, including the legacy AUTH= advertisement.
SmtpMailer STARTTLS accepts only TLS 1.2 and 1.3, reports the actual handshake failure reason instead of a bare &quot;Unable to connect&quot;, and defaults to the submission port 587.
FallbackMailer no longer keeps retrying a mailer whose failure is permanent, like rejected credentials – retrying cannot fix those.
DkimSigner relaxed canonicalization collapses every whitespace sequence, including tabs, so signatures on such headers verify everywhere.
</description>
		<content:encoded><![CDATA[
		<p>This release teaches SmtpMailer to speak OAuth, DkimSigner to sign with Ed25519, and CssInliner to resolve styles the way a browser does. Add a DKIM security fix and the deliverability headers Gmail and Yahoo now demand, and there is a good reason to upgrade even if you never hit any of the fixed bugs.</p>
<h2>🔒 Security</h2>
<ul>
<li><strong>DkimSigner</strong> no longer emits the <code>l=</code> body-length tag. With it, anyone could append arbitrary content to a signed message without invalidating the signature.</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong>SmtpMailer::setAccessToken()</strong> – authenticates with an OAuth 2.0 access token (XOAUTH2), which Gmail and Microsoft 365 require now that they are retiring passwords for SMTP. Pass the token as a string, or as a callback that is called on each connection so an expiring token gets refreshed.</li>
<li><strong>Message::setUnsubscribe()</strong> – emits the pair of one-click unsubscribe headers (RFC 8058) that Gmail and Yahoo require from bulk senders. Getting the two headers to agree is exactly the kind of detail that is easy to get wrong by hand; the headers are also DKIM-signed, so the unsubscribe target cannot be swapped in transit.</li>
<li><strong>DkimSigner</strong> signs with Ed25519 keys (RFC 8463). The algorithm is detected from the key itself, so no new argument is needed. New header oversigning (opt-in via <code>$oversignHeaders</code>) makes appending a second <code>From:</code> header break the signature.</li>
<li><strong>FileMailer</strong> – a mailer that writes each message to an <code>.eml</code> file instead of sending it; ideal for development and testing.</li>
<li>Addresses with internationalized domains – jan@příklad.cz – are converted to punycode automatically, so they work with ordinary SMTP servers instead of failing with a puzzling server error.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>CssInliner</strong> resolves competing declarations by the real CSS cascade – <code>!important</code>, inline styles, selector specificity, source order – instead of letting the last rule win. Inlined emails now look like the page the stylesheet was written for, and each property is written out once, with the winning value.</li>
<li><strong>CssInliner</strong> no longer turns <code>width: auto</code> or <code>calc(...)</code> into <code>width="0"</code> (which collapsed the cell in Outlook), and treats property names case-insensitively, as CSS does.</li>
<li>Header names are case-insensitive per RFC 5322: <code>getHeader('from')</code> finds the <code>From</code> header, <code>setHeader('SUBJECT')</code> replaces the existing Subject instead of adding a second one, and DKIM signing matches headers whatever their spelling.</li>
<li><strong>SmtpMailer</strong> got a robustness overhaul: a persistent connection dropped by an idle server is detected and re-established instead of failing every send from then on; large messages are no longer silently truncated when the socket buffer fills up; the read timeout holds even against a server that never stops talking; and authentication picks only from mechanisms the server actually offers, including the legacy <code>AUTH=</code> advertisement.</li>
<li><strong>SmtpMailer</strong> STARTTLS accepts only TLS 1.2 and 1.3, reports the actual handshake failure reason instead of a bare "Unable to connect", and defaults to the submission port 587.</li>
<li><strong>FallbackMailer</strong> no longer keeps retrying a mailer whose failure is permanent, like rejected credentials – retrying cannot fix those.</li>
<li><strong>DkimSigner</strong> relaxed canonicalization collapses every whitespace sequence, including tabs, so signatures on such headers verify everywhere.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 27 Jul 2026 15:39:36 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/mail/releases/tag/untagged-eba1b214f5c37cb81cd9</guid>
	</item>
	<item>
		<title>Latte v3.1.6</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.6</link>
		<description>A substantial correctness and security release born from a deep audit of the engine. It hardens context-sensitive escaping in two spots, fixes a long list of filter and compiler edge cases, adds the handy |map filter and an afterRender() extension hook, and brings back a performance regression fix. A recommended upgrade for everyone.
💥 Behavior Changes &amp; Deprecations

{$interval|date} without an explicit format now throws instead of silently printing the literal format string j. n. Y. Pass a format for DateInterval, e.g. {$interval|date: &apos;%d days&apos;}.
{first}, {last}, {sep} used outside a {foreach} now emit a deprecation warning – they rely on an ambient $iterator that only a loop provides. This becomes a compile-time error in Latte 3.2.

✨ New Features

New |map filter – transform every item with a callback, the natural partner to |filter: {foreach ($items|map: fn($x) =&gt; $x-&gt;name) as $name}.
New Extension::afterRender() hook – called in a finally, so it runs even when rendering ends early via {exitIf} or is interrupted by an exception. Perfect for cleanup or measurement.
The Tracy panel now shows render time per template, both total and self (excluding nested templates), so you can finally see which template actually eats the time.
|last, |random, |implode/|join, |commas now accept any iterable, not just arrays – hand them a generator or iterator directly, just like |first, |slice and |filter already allowed.

🐛 Bug Fixes

Security: &lt;script type=&quot; text/javascript &quot;&gt; with surrounding whitespace was classified as raw text while browsers execute it as JavaScript. The type is now trimmed the way browsers do, so context-sensitive escaping kicks in correctly.
Security: a template compiled under a permissive sandbox policy could be silently reused from cache under a stricter one, because part of the sandbox is enforced at compile time. Policy rules are now part of the cache key.
Security: xlink:href in inline SVG is now treated as a URL attribute and sanitized like href.
{capture $x|filter} no longer double-escapes its content. Adding an innocent filter like |trim used to strip the &quot;HTML-ness&quot; of the captured markup, escaping it on output; captured HTML now stays intact (while a filter that changes the content type still yields a plain string).
{switch} with no expression used to compile to invalid PHP; it now works as a switch-true idiom ({case $cond}).
&lt;script type=&quot;a{$dyn}&quot;&gt; with a partially dynamic type attribute no longer fails compilation with a cryptic &quot;Unhandled match case&quot; – it&apos;s treated as JavaScript.
The empty comment {**} no longer breaks compilation.
|reverse and |column no longer drop elements from generators or iterators that yield duplicate keys.
|indent no longer interprets $ or \ in the indentation string as regular-expression backreferences.
|explode/|split (and |random) now raise a clear RuntimeException on malformed UTF-8 instead of a confusing TypeError.
|padLeft/|padRight with an empty pad string, and the divisibleBy() function with a zero divisor, now throw a helpful message instead of a raw DivisionByZeroError.
Compiled template class names now use a 64-bit hash (up from 40-bit), removing a small but real risk of two templates colliding so that one silently renders the other.
Custom n:attributes whose name contains tag- or inner- (e.g. n:my-tag-attr) are no longer mangled by the prefix stripper.
Extensions that subclass core nodes no longer silently break {iterateWhile}, {rollback} and {include parent} – Tag::closestTag() now matches subclasses, as its documentation always promised.
A compile-time failure without a cache directory now surfaces as a proper CompileException pointing at the generated source, instead of a bare ParseError.

⚡ Performance

The engine no longer recomputes its entire configuration signature on every {include}, {extends} or {embed} – a memoization lost in the 3.1 cache refactor is restored (and properly invalidated whenever you reconfigure the engine). This also fixes a crash when createTemplate(clearCache: false) was the very first call.
Passing a parameters object to render() is roughly 2.6× faster – the reflection scan of the parameter class is memoized per class instead of being repeated on every render.
</description>
		<content:encoded><![CDATA[
		<p>A substantial correctness and security release born from a deep audit of the engine. It hardens context-sensitive escaping in two spots, fixes a long list of filter and compiler edge cases, adds the handy <strong>|map</strong> filter and an <strong>afterRender()</strong> extension hook, and brings back a performance regression fix. A recommended upgrade for everyone.</p>
<h2>💥 Behavior Changes &amp; Deprecations</h2>
<ul>
<li><strong><code>{$interval|date}</code></strong> without an explicit format now throws instead of silently printing the literal format string <code>j. n. Y</code>. Pass a format for <code>DateInterval</code>, e.g. <code>{$interval|date: '%d days'}</code>.</li>
<li><strong><code>{first}</code>, <code>{last}</code>, <code>{sep}</code></strong> used outside a <code>{foreach}</code> now emit a deprecation warning – they rely on an ambient <code>$iterator</code> that only a loop provides. This becomes a compile-time error in Latte 3.2.</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li>New <strong><code>|map</code></strong> filter – transform every item with a callback, the natural partner to <code>|filter</code>: <code>{foreach ($items|map: fn($x) =&gt; $x-&gt;name) as $name}</code>.</li>
<li>New <strong><code>Extension::afterRender()</code></strong> hook – called in a <code>finally</code>, so it runs even when rendering ends early via <code>{exitIf}</code> or is interrupted by an exception. Perfect for cleanup or measurement.</li>
<li>The <strong>Tracy panel</strong> now shows render time per template, both total and self (excluding nested templates), so you can finally see which template actually eats the time.</li>
<li><strong><code>|last</code>, <code>|random</code>, <code>|implode</code>/<code>|join</code>, <code>|commas</code></strong> now accept any <code>iterable</code>, not just arrays – hand them a generator or iterator directly, just like <code>|first</code>, <code>|slice</code> and <code>|filter</code> already allowed.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Security:</strong> <code>&lt;script type=" text/javascript "&gt;</code> with surrounding whitespace was classified as raw text while browsers execute it as JavaScript. The type is now trimmed the way browsers do, so context-sensitive escaping kicks in correctly.</li>
<li><strong>Security:</strong> a template compiled under a permissive sandbox policy could be silently reused from cache under a stricter one, because part of the sandbox is enforced at compile time. Policy rules are now part of the cache key.</li>
<li><strong>Security:</strong> <code>xlink:href</code> in inline SVG is now treated as a URL attribute and sanitized like <code>href</code>.</li>
<li><strong><code>{capture $x|filter}</code></strong> no longer double-escapes its content. Adding an innocent filter like <code>|trim</code> used to strip the "HTML-ness" of the captured markup, escaping it on output; captured HTML now stays intact (while a filter that changes the content type still yields a plain string).</li>
<li><strong><code>{switch}</code></strong> with no expression used to compile to invalid PHP; it now works as a switch-true idiom (<code>{case $cond}</code>).</li>
<li><strong><code>&lt;script type="a{$dyn}"&gt;</code></strong> with a partially dynamic type attribute no longer fails compilation with a cryptic <em>"Unhandled match case"</em> – it's treated as JavaScript.</li>
<li>The empty comment <strong><code>{**}</code></strong> no longer breaks compilation.</li>
<li><strong><code>|reverse</code></strong> and <strong><code>|column</code></strong> no longer drop elements from generators or iterators that yield duplicate keys.</li>
<li><strong><code>|indent</code></strong> no longer interprets <code>$</code> or <code>\</code> in the indentation string as regular-expression backreferences.</li>
<li><strong><code>|explode</code>/<code>|split</code></strong> (and <strong><code>|random</code></strong>) now raise a clear <code>RuntimeException</code> on malformed UTF-8 instead of a confusing <code>TypeError</code>.</li>
<li><strong><code>|padLeft</code>/<code>|padRight</code></strong> with an empty pad string, and the <strong><code>divisibleBy()</code></strong> function with a zero divisor, now throw a helpful message instead of a raw <code>DivisionByZeroError</code>.</li>
<li>Compiled template class names now use a 64-bit hash (up from 40-bit), removing a small but real risk of two templates colliding so that one silently renders the other.</li>
<li>Custom <strong>n:attributes</strong> whose name contains <code>tag-</code> or <code>inner-</code> (e.g. <code>n:my-tag-attr</code>) are no longer mangled by the prefix stripper.</li>
<li>Extensions that subclass core nodes no longer silently break <code>{iterateWhile}</code>, <code>{rollback}</code> and <code>{include parent}</code> – <strong><code>Tag::closestTag()</code></strong> now matches subclasses, as its documentation always promised.</li>
<li>A compile-time failure without a cache directory now surfaces as a proper <code>CompileException</code> pointing at the generated source, instead of a bare <code>ParseError</code>.</li>
</ul>
<h2>⚡ Performance</h2>
<ul>
<li>The engine no longer recomputes its entire configuration signature on every <code>{include}</code>, <code>{extends}</code> or <code>{embed}</code> – a memoization lost in the 3.1 cache refactor is restored (and properly invalidated whenever you reconfigure the engine). This also fixes a crash when <code>createTemplate(clearCache: false)</code> was the very first call.</li>
<li>Passing a <strong>parameters object</strong> to <code>render()</code> is roughly <strong>2.6× faster</strong> – the reflection scan of the parameter class is memoized per class instead of being repeated on every render.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 27 Jul 2026 15:34:55 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.6</guid>
	</item>
	<item>
		<title>Latte v3.1.5</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.5</link>
		<description>Template inheritance just got a lot more flexible: layouts can now receive explicit variables, {embed} supports an implicit default block, and blocks finally behave intuitively in places where they used to fail. On top of that, the whitespace minifier behind {spaceless} has been rewritten from scratch to actually understand HTML.
✨ New Features

{spaceless} rewritten from the ground up – the minifier now truly understands HTML, so it squeezes out much more whitespace without ever breaking your page: it strips whitespace completely around block elements, keeps proper word spacing around inline tags like &lt;i&gt; or &lt;a&gt;, and leaves pre, textarea, script, style and attribute values untouched. And it streams, so even huge templates minify with no memory overhead.
Implicit default block for {embed} – content written directly inside {embed} without a {block} wrapper now overrides {block default} of the embedded template, while an empty {embed} keeps the fallback (#419)
{layout file, vars} – pass explicit variables straight to the parent template: {layout &apos;parent.latte&apos;, title: &apos;Hello&apos;}. They reach the layout only (child blocks don&apos;t see them) and override same-named parameters. Works with {extends} too; note the comma before the arguments is required.
|json attribute modifier – JSON-encode a dynamic HTML attribute value with smart quoting: &lt;div data-config={$config|json}&gt;

🐛 Bug Fixes

{include parent} and {include this} now work inside dynamically named blocks – previously this was a compile error, or worse, silently bound to an outer static block
{contentType} inside &lt;script&gt; now really switches the escaping context – previously it was a silent no-op unless the script element had a matching type attribute

🛠 For Extension Developers

Every AST node now carries its full source extent: Node::$position marks the start and the new Node::$end the exclusive end; Range is a standalone start/end value object again (this reverts the shape shipped in 3.1.4)
</description>
		<content:encoded><![CDATA[
		<p>Template inheritance just got a lot more flexible: layouts can now receive explicit variables, <code>{embed}</code> supports an implicit default block, and blocks finally behave intuitively in places where they used to fail. On top of that, the whitespace minifier behind <code>{spaceless}</code> has been rewritten from scratch to actually understand HTML.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>{spaceless} rewritten from the ground up</strong> – the minifier now truly understands HTML, so it squeezes out much more whitespace without ever breaking your page: it strips whitespace completely around block elements, keeps proper word spacing around inline tags like <code>&lt;i&gt;</code> or <code>&lt;a&gt;</code>, and leaves <code>pre</code>, <code>textarea</code>, <code>script</code>, <code>style</code> and attribute values untouched. And it streams, so even huge templates minify with no memory overhead.</li>
<li><strong>Implicit default block for {embed}</strong> – content written directly inside <code>{embed}</code> without a <code>{block}</code> wrapper now overrides <code>{block default}</code> of the embedded template, while an empty <code>{embed}</code> keeps the fallback (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4675105687" data-permission-text="Title is private" data-url="https://github.com/nette/latte/issues/419" data-hovercard-type="pull_request" data-hovercard-url="/nette/latte/pull/419/hovercard" href="https://github.com/nette/latte/pull/419">#419</a>)</li>
<li><strong>{layout file, vars}</strong> – pass explicit variables straight to the parent template: <code>{layout 'parent.latte', title: 'Hello'}</code>. They reach the layout only (child blocks don't see them) and override same-named parameters. Works with <code>{extends}</code> too; note the comma before the arguments is required.</li>
<li><strong>|json attribute modifier</strong> – JSON-encode a dynamic HTML attribute value with smart quoting: <code>&lt;div data-config={$config|json}&gt;</code></li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><code>{include parent}</code> and <code>{include this}</code> now work inside dynamically named blocks – previously this was a compile error, or worse, silently bound to an outer static block</li>
<li><code>{contentType}</code> inside <code>&lt;script&gt;</code> now really switches the escaping context – previously it was a silent no-op unless the script element had a matching <code>type</code> attribute</li>
</ul>
<h2>🛠 For Extension Developers</h2>
<ul>
<li>Every AST node now carries its full source extent: <code>Node::$position</code> marks the start and the new <code>Node::$end</code> the exclusive end; <code>Range</code> is a standalone start/end value object again (this reverts the shape shipped in 3.1.4)</li>
</ul>
		]]></content:encoded>
		<pubDate>Sat, 25 Jul 2026 15:46:54 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.5</guid>
	</item>
	<item>
		<title>Security v3.2.6</title>
		<link>https://github.com/nette/security/releases/tag/v3.2.6</link>
		<description>✨ New Features

Hashed passwords in SimpleAuthenticator – stored passwords may now be crypt-format hashes (anything password_hash() produces) and can be freely mixed with plain-text ones. The format is detected automatically, so hashes just work in the security: users: config section with no extra option. A hash whose algorithm the PHP build doesn&apos;t know fails closed instead of being compared as plain text, and plain-text comparison is timing-safe.
Passwords::bcrypt() and Passwords::argon2id() – name the algorithm instead of juggling PASSWORD_* constants and options arrays: Passwords::bcrypt(12) or Passwords::argon2id(memoryCost: 65536). Omitted parameters keep PHP&apos;s defaults, and argon2id() fails with a clear exception on builds without Argon2 support.
ACL rules in the configuration – the new rules section lets you define permissions declaratively next to your roles and resources:
security:
    rules:
        allow:
            - [guest, article, view]
            - [registered, comment, [add, edit]]
            - [admin]
        deny:
            - [banned, comment, add]
Each rule is [role(s), resource(s), privilege(s)]; an omitted or null item means &quot;all&quot;, and a bare string grants or revokes everything for that role. Malformed rules are rejected at config time, not at runtime.

🐛 Bug Fixes

logout() no longer touches the storage when there is nothing to change, so logging out a guest doesn&apos;t needlessly regenerate the session ID or overwrite the logout reason. A stored authentication vetoed by wakeupIdentity() (a revoked token, say) is still properly cleared.
Permission::isAllowed() now saves and restores the queried role and resource, making it re-entrant and exception-safe – an assertion callback can call isAllowed() again without corrupting the results of the outer query.
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li><strong>Hashed passwords in <code>SimpleAuthenticator</code></strong> – stored passwords may now be crypt-format hashes (anything <code>password_hash()</code> produces) and can be freely mixed with plain-text ones. The format is detected automatically, so hashes just work in the <code>security: users:</code> config section with no extra option. A hash whose algorithm the PHP build doesn't know fails closed instead of being compared as plain text, and plain-text comparison is timing-safe.</li>
<li><strong><code>Passwords::bcrypt()</code> and <code>Passwords::argon2id()</code></strong> – name the algorithm instead of juggling <code>PASSWORD_*</code> constants and options arrays: <code>Passwords::bcrypt(12)</code> or <code>Passwords::argon2id(memoryCost: 65536)</code>. Omitted parameters keep PHP's defaults, and <code>argon2id()</code> fails with a clear exception on builds without Argon2 support.</li>
<li><strong>ACL rules in the configuration</strong> – the new <code>rules</code> section lets you define permissions declaratively next to your roles and resources:
<div class="highlight highlight-source-neon notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="security:
    rules:
        allow:
            - [guest, article, view]
            - [registered, comment, [add, edit]]
            - [admin]
        deny:
            - [banned, comment, add]"><pre><span class="pl-ent">security</span><span class="pl-k">:</span>
    <span class="pl-ent">rules</span><span class="pl-k">:</span>
        <span class="pl-ent">allow</span><span class="pl-k">:</span>
            <span class="pl-s">- [guest</span>, <span class="pl-s">article</span>, <span class="pl-s">view</span>]
            <span class="pl-s">- [registered</span>, <span class="pl-s">comment</span>, [<span class="pl-s">add</span>, <span class="pl-s">edit</span>]]
            <span class="pl-s">- [admin</span>]
        <span class="pl-ent">deny</span><span class="pl-k">:</span>
            <span class="pl-s">- [banned</span>, <span class="pl-s">comment</span>, <span class="pl-s">add</span>]</pre></div>
Each rule is <code>[role(s), resource(s), privilege(s)]</code>; an omitted or null item means "all", and a bare string grants or revokes everything for that role. Malformed rules are rejected at config time, not at runtime.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><code>logout()</code> no longer touches the storage when there is nothing to change, so logging out a guest doesn't needlessly regenerate the session ID or overwrite the logout reason. A stored authentication vetoed by <code>wakeupIdentity()</code> (a revoked token, say) is still properly cleared.</li>
<li><code>Permission::isAllowed()</code> now saves and restores the queried role and resource, making it re-entrant and exception-safe – an assertion callback can call <code>isAllowed()</code> again without corrupting the results of the outer query.</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 24 Jul 2026 23:44:31 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/security/releases/tag/v3.2.6</guid>
	</item>
	<item>
		<title>Utils v4.1.5</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.5</link>
		<description>This release adds an immutable date/time class, makes file writes safer, background processes possible, and Finder masks smarter. Plus a couple of bug fixes worth picking up.
✨ New Features

DateTimeImmutable – a new immutable counterpart to Nette\Utils\DateTime. It extends PHP&apos;s \DateTimeImmutable with strict validation (invalid dates and times throw instead of being silently rolled over), convenient factories from() and fromParts(), DST-safe relative modifications, and JSON serialization.
FileSystem::writeAtomic() – writes a file atomically via a temporary file and rename, so a concurrent reader never sees it partially written or truncated. Ideal for caches and generated configs.
Process::detach() – lets a process keep running in the background after the Process object is destroyed, instead of being killed by the destructor. Output must go to a file or be discarded, since nobody reads the pipes after detaching.
Process – on Windows with PHP 8.5, captured output now flows through real pipes instead of temporary files, thanks to the fixed stream_select().
Html::fragment() and add() – create a nameless element pre-filled with children, or append children to an existing element. Unlike addHtml(), plain strings are escaped by default and nulls are skipped.
Html::text() and Html::html() – new static factories replacing fromText() and fromHtml(), which are now deprecated.
Finder – the mask now fully drives recursion: **/foo together with in() searches recursively, and the ** short form expands like in zsh, so test/** means test/**/* and **.c means **/*.c (previously such masks silently degraded to a single *).
Finder – a trailing slash in a find() mask matches directories only: find(&apos;temp/&apos;).
Finder::exclude() – now uses the same mask grammar as find(): **.txt works, ./ anchors to the search root, and a trailing /, /* or /** controls whether the directory itself, its contents, or both are excluded.
Finder – paths are no longer normalized to forward slashes; they stay in their native form, which also fixes corruption of backslashes in POSIX file names. Note: on Windows, returned paths may now contain backslashes where they used to be unified.

🐛 Bug Fixes

ArrayList::prepend() – no longer misbehaves on an empty list.
Validators::isUrl() – now rejects malformed IPv4 addresses with octets above 255, so nonsense like http://999.1.1.1 no longer passes as a valid URL.
Strings::compare() – tolerates invalid UTF-8 instead of failing when the Normalizer gives up.
Strings::length() – the fallback used when neither mbstring nor iconv is available no longer relies on the deprecated utf8_decode(), so it stays quiet on PHP 8.2+.
Finder::exclude() – exclude(&apos;subdir/&apos;) silently excluded nothing due to a greedy regex; the trailing /, /* and /** variants now work as documented.
</description>
		<content:encoded><![CDATA[
		<p>This release adds an immutable date/time class, makes file writes safer, background processes possible, and Finder masks smarter. Plus a couple of bug fixes worth picking up.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>DateTimeImmutable</strong> – a new immutable counterpart to <code>Nette\Utils\DateTime</code>. It extends PHP's <code>\DateTimeImmutable</code> with strict validation (invalid dates and times throw instead of being silently rolled over), convenient factories <code>from()</code> and <code>fromParts()</code>, DST-safe relative modifications, and JSON serialization.</li>
<li><strong>FileSystem::writeAtomic()</strong> – writes a file atomically via a temporary file and rename, so a concurrent reader never sees it partially written or truncated. Ideal for caches and generated configs.</li>
<li><strong>Process::detach()</strong> – lets a process keep running in the background after the <code>Process</code> object is destroyed, instead of being killed by the destructor. Output must go to a file or be discarded, since nobody reads the pipes after detaching.</li>
<li><strong>Process</strong> – on Windows with PHP 8.5, captured output now flows through real pipes instead of temporary files, thanks to the fixed <code>stream_select()</code>.</li>
<li><strong>Html::fragment()</strong> and <strong>add()</strong> – create a nameless element pre-filled with children, or append children to an existing element. Unlike <code>addHtml()</code>, plain strings are escaped by default and nulls are skipped.</li>
<li><strong>Html::text()</strong> and <strong>Html::html()</strong> – new static factories replacing <code>fromText()</code> and <code>fromHtml()</code>, which are now deprecated.</li>
<li><strong>Finder</strong> – the mask now fully drives recursion: <code>**/foo</code> together with <code>in()</code> searches recursively, and the <code>**</code> short form expands like in zsh, so <code>test/**</code> means <code>test/**/*</code> and <code>**.c</code> means <code>**/*.c</code> (previously such masks silently degraded to a single <code>*</code>).</li>
<li><strong>Finder</strong> – a trailing slash in a <code>find()</code> mask matches directories only: <code>find('temp/')</code>.</li>
<li><strong>Finder::exclude()</strong> – now uses the same mask grammar as <code>find()</code>: <code>**.txt</code> works, <code>./</code> anchors to the search root, and a trailing <code>/</code>, <code>/*</code> or <code>/**</code> controls whether the directory itself, its contents, or both are excluded.</li>
<li><strong>Finder</strong> – paths are no longer normalized to forward slashes; they stay in their native form, which also fixes corruption of backslashes in POSIX file names. Note: on Windows, returned paths may now contain backslashes where they used to be unified.</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>ArrayList::prepend()</strong> – no longer misbehaves on an empty list.</li>
<li><strong>Validators::isUrl()</strong> – now rejects malformed IPv4 addresses with octets above 255, so nonsense like <code>http://999.1.1.1</code> no longer passes as a valid URL.</li>
<li><strong>Strings::compare()</strong> – tolerates invalid UTF-8 instead of failing when the Normalizer gives up.</li>
<li><strong>Strings::length()</strong> – the fallback used when neither <code>mbstring</code> nor <code>iconv</code> is available no longer relies on the deprecated <code>utf8_decode()</code>, so it stays quiet on PHP 8.2+.</li>
<li><strong>Finder::exclude()</strong> – <code>exclude('subdir/')</code> silently excluded nothing due to a greedy regex; the trailing <code>/</code>, <code>/*</code> and <code>/**</code> variants now work as documented.</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 17 Jul 2026 23:09:52 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.5</guid>
	</item>
	<item>
		<title>Application v3.2.12</title>
		<link>https://github.com/nette/application/releases/tag/v3.2.12</link>
		<description>A hardening release. Crafted or malformed request parameters that used to slip through as uncaught 500s now degrade gracefully to 4xx. If your site gets probed by scanners – and it does – these three fixes turn a batch of &quot;Server Error&quot; reports into clean Bad Request / Not Found responses.

Self-links no longer crash on bad input – when a presenter builds a link to the current page (redirect(&apos;this&apos;), forward(&apos;this&apos;), isLinkCurrent(&apos;this&apos;), typically from a language switcher) while the current URL carries a parameter that doesn&apos;t fit the action&apos;s typed signature (e.g. ?id=abc for int $id), the framework raised an uncaught InvalidLinkException (HTTP 500). It now reports a proper BadRequestException (4xx) through the new InvalidRequestParameterException. Explicitly passed bad link arguments still throw InvalidLinkException, so genuine programmer mistakes stay visible.
Numeric component ids no longer trigger a TypeError – a crafted query key such as ?1-foo=bar produced a numeric component id that hit getComponent()&apos;s string type hint and threw a TypeError (HTTP 500). The id is now cast to string and the request is handled gracefully.
Routing panel survives weird parameters – a request like ?do[]=x could crash Tracy&apos;s routing panel during development. It now skips non-string presenter/signal/action values instead of throwing.
</description>
		<content:encoded><![CDATA[
		<p>A hardening release. Crafted or malformed request parameters that used to slip through as uncaught <strong>500s</strong> now degrade gracefully to <strong>4xx</strong>. If your site gets probed by scanners – and it does – these three fixes turn a batch of "Server Error" reports into clean Bad Request / Not Found responses.</p>
<ul>
<li><strong>Self-links no longer crash on bad input</strong> – when a presenter builds a link to the current page (<code>redirect('this')</code>, <code>forward('this')</code>, <code>isLinkCurrent('this')</code>, typically from a language switcher) while the current URL carries a parameter that doesn't fit the action's typed signature (e.g. <code>?id=abc</code> for <code>int $id</code>), the framework raised an uncaught <code>InvalidLinkException</code> (HTTP 500). It now reports a proper <code>BadRequestException</code> (4xx) through the new <strong><code>InvalidRequestParameterException</code></strong>. Explicitly passed bad link arguments still throw <code>InvalidLinkException</code>, so genuine programmer mistakes stay visible.</li>
<li><strong>Numeric component ids no longer trigger a TypeError</strong> – a crafted query key such as <code>?1-foo=bar</code> produced a numeric component id that hit <code>getComponent()</code>'s <code>string</code> type hint and threw a <code>TypeError</code> (HTTP 500). The id is now cast to string and the request is handled gracefully.</li>
<li><strong>Routing panel survives weird parameters</strong> – a request like <code>?do[]=x</code> could crash Tracy's routing panel during development. It now skips non-string presenter/signal/action values instead of throwing.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 29 Jun 2026 19:06:50 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/v3.2.12</guid>
	</item>
	<item>
		<title>Application v3.2.11</title>
		<link>https://github.com/nette/application/releases/tag/v3.2.11</link>
		<description>A hardening release. Crafted or malformed request parameters that used to slip through as uncaught 500s now degrade gracefully to 4xx. If your site gets probed by scanners – and it does – these three fixes turn a batch of &quot;Server Error&quot; reports into clean Bad Request / Not Found responses.

Self-links no longer crash on bad input – when a presenter builds a link to the current page (redirect(&apos;this&apos;), forward(&apos;this&apos;), isLinkCurrent(&apos;this&apos;), typically from a language switcher) while the current URL carries a parameter that doesn&apos;t fit the action&apos;s typed signature (e.g. ?id=abc for int $id), the framework raised an uncaught InvalidLinkException (HTTP 500). It now reports a proper BadRequestException (4xx) through the new InvalidRequestParameterException. Explicitly passed bad link arguments still throw InvalidLinkException, so genuine programmer mistakes stay visible.
Numeric component ids no longer trigger a TypeError – a crafted query key such as ?1-foo=bar produced a numeric component id that hit getComponent()&apos;s string type hint and threw a TypeError (HTTP 500). The id is now cast to string and the request is handled gracefully.
Routing panel survives weird parameters – a request like ?do[]=x could crash Tracy&apos;s routing panel during development. It now skips non-string presenter/signal/action values instead of throwing.
</description>
		<content:encoded><![CDATA[
		<p>A hardening release. Crafted or malformed request parameters that used to slip through as uncaught <strong>500s</strong> now degrade gracefully to <strong>4xx</strong>. If your site gets probed by scanners – and it does – these three fixes turn a batch of "Server Error" reports into clean Bad Request / Not Found responses.</p>
<ul>
<li><strong>Self-links no longer crash on bad input</strong> – when a presenter builds a link to the current page (<code>redirect('this')</code>, <code>forward('this')</code>, <code>isLinkCurrent('this')</code>, typically from a language switcher) while the current URL carries a parameter that doesn't fit the action's typed signature (e.g. <code>?id=abc</code> for <code>int $id</code>), the framework raised an uncaught <code>InvalidLinkException</code> (HTTP 500). It now reports a proper <code>BadRequestException</code> (4xx) through the new <strong><code>InvalidRequestParameterException</code></strong>. Explicitly passed bad link arguments still throw <code>InvalidLinkException</code>, so genuine programmer mistakes stay visible.</li>
<li><strong>Numeric component ids no longer trigger a TypeError</strong> – a crafted query key such as <code>?1-foo=bar</code> produced a numeric component id that hit <code>getComponent()</code>'s <code>string</code> type hint and threw a <code>TypeError</code> (HTTP 500). The id is now cast to string and the request is handled gracefully.</li>
<li><strong>Routing panel survives weird parameters</strong> – a request like <code>?do[]=x</code> could crash Tracy's routing panel during development. It now skips non-string presenter/signal/action values instead of throwing.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 29 Jun 2026 19:00:50 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/v3.2.11</guid>
	</item>
	<item>
		<title>Application v3.2.11</title>
		<link>https://github.com/nette/application/releases/tag/untagged-24598616f7e9d092d5cd</link>
		<description>A hardening release. Crafted or malformed request parameters that used to slip through as uncaught 500s now degrade gracefully to 4xx. If your site gets probed by scanners – and it does – these three fixes turn a batch of &quot;Server Error&quot; reports into clean Bad Request / Not Found responses.

Self-links no longer crash on bad input – when a presenter builds a link to the current page (redirect(&apos;this&apos;), forward(&apos;this&apos;), isLinkCurrent(&apos;this&apos;), typically from a language switcher) while the current URL carries a parameter that doesn&apos;t fit the action&apos;s typed signature (e.g. ?id=abc for int $id), the framework raised an uncaught InvalidLinkException (HTTP 500). It now reports a proper BadRequestException (4xx) through the new InvalidRequestParameterException. Explicitly passed bad link arguments still throw InvalidLinkException, so genuine programmer mistakes stay visible.
Numeric component ids no longer trigger a TypeError – a crafted query key such as ?1-foo=bar produced a numeric component id that hit getComponent()&apos;s string type hint and threw a TypeError (HTTP 500). The id is now cast to string and the request is handled gracefully.
Routing panel survives weird parameters – a request like ?do[]=x could crash Tracy&apos;s routing panel during development. It now skips non-string presenter/signal/action values instead of throwing.
</description>
		<content:encoded><![CDATA[
		<p>A hardening release. Crafted or malformed request parameters that used to slip through as uncaught <strong>500s</strong> now degrade gracefully to <strong>4xx</strong>. If your site gets probed by scanners – and it does – these three fixes turn a batch of "Server Error" reports into clean Bad Request / Not Found responses.</p>
<ul>
<li><strong>Self-links no longer crash on bad input</strong> – when a presenter builds a link to the current page (<code>redirect('this')</code>, <code>forward('this')</code>, <code>isLinkCurrent('this')</code>, typically from a language switcher) while the current URL carries a parameter that doesn't fit the action's typed signature (e.g. <code>?id=abc</code> for <code>int $id</code>), the framework raised an uncaught <code>InvalidLinkException</code> (HTTP 500). It now reports a proper <code>BadRequestException</code> (4xx) through the new <strong><code>InvalidRequestParameterException</code></strong>. Explicitly passed bad link arguments still throw <code>InvalidLinkException</code>, so genuine programmer mistakes stay visible.</li>
<li><strong>Numeric component ids no longer trigger a TypeError</strong> – a crafted query key such as <code>?1-foo=bar</code> produced a numeric component id that hit <code>getComponent()</code>'s <code>string</code> type hint and threw a <code>TypeError</code> (HTTP 500). The id is now cast to string and the request is handled gracefully.</li>
<li><strong>Routing panel survives weird parameters</strong> – a request like <code>?do[]=x</code> could crash Tracy's routing panel during development. It now skips non-string presenter/signal/action values instead of throwing.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 29 Jun 2026 19:00:50 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/untagged-24598616f7e9d092d5cd</guid>
	</item>
	<item>
		<title>Application v3.3.0</title>
		<link>https://github.com/nette/application/releases/tag/v3.3.0</link>
		<description>Nette Application 3.3 modernizes the foundations: PHP 8.3+ and Latte 3.1, more reliable CSRF protection driven by the browser itself, and a default presenter mapping that finally matches the structure used throughout the documentation. It also clears out a pile of long-forgotten legacy. Please test the RC and report anything that breaks before the stable release.
💥 Breaking Changes

PHP 8.3 – 8.5 and Latte 3.1 are now required
More reliable CSRF protection – same-origin is now verified via the browser&apos;s Sec-Fetch-Site header instead of a SameSite cookie.
Default presenter mapping is now App\Presentation\*\**Presenter
Application::processRequest() returns a Response instead of sending it itself (#350) – sending is handled by run(). This enables long-running runtimes (RoadRunner, FrankenPHP) and PSR integration.
Presenter::getRequest() throws instead of returning null when the presenter isn&apos;t running yet
LatteFactory::create() now takes ?Control – update any custom LatteFactory implementation to the new create(?Control $control = null) signature.
Removed {ifCurrent} – use {if isLinkCurrent(&apos;...&apos;)}.
Removed compatibility with old class names such as PresenterComponent and IRouter.

⚠️ Deprecations
Mostly very old curiosities that few people knew existed – they still work but now emit a deprecation notice:

@annotations → PHP attributes: @persistent → #[Persistent], @crossOrigin → #[Requires(sameOrigin: false)], @deprecated → #[Deprecated].
Array access on RouteList – $router[] = new Route(...) and friends are replaced by $router-&gt;addRoute(...) / getRouters().
Query string in a link destination – link(&apos;Product:detail?id=1&apos;) should pass arguments instead: link(&apos;Product:detail&apos;, [&apos;id&apos; =&gt; 1]).
Component::getParameter() second $default argument – use the ?? operator instead.
Some magic properties ($presenter-&gt;view, $layout, $request, $session…) – use the getters.

✨ New Features

Set the URL fragment straight from arguments – link(&apos;Product:detail&apos;, [&apos;#&apos; =&gt; &apos;reviews&apos;]) produces ...#reviews. The value is URL-encoded, must be scalar, and isn&apos;t passed on as a request parameter.
New Presenter::completeTemplate() – a protected method extracted from sendTemplate() that you can override to inject shared variables or set the template file before rendering.
</description>
		<content:encoded><![CDATA[
		<p>Nette Application 3.3 modernizes the foundations: PHP 8.3+ and Latte 3.1, more reliable CSRF protection driven by the browser itself, and a default presenter mapping that finally matches the structure used throughout the documentation. It also clears out a pile of long-forgotten legacy. Please test the RC and report anything that breaks before the stable release.</p>
<h2>💥 Breaking Changes</h2>
<ul>
<li><strong>PHP 8.3 – 8.5 and Latte 3.1 are now required</strong></li>
<li><strong>More reliable CSRF protection</strong> – same-origin is now verified via the browser's <code>Sec-Fetch-Site</code> header instead of a SameSite cookie.</li>
<li><strong>Default presenter mapping is now <code>App\Presentation\*\**Presenter</code></strong></li>
<li><strong><code>Application::processRequest()</code> returns a <code>Response</code></strong> instead of sending it itself (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3166208456" data-permission-text="Title is private" data-url="https://github.com/nette/application/issues/350" data-hovercard-type="pull_request" data-hovercard-url="/nette/application/pull/350/hovercard" href="https://github.com/nette/application/pull/350">#350</a>) – sending is handled by <code>run()</code>. This enables long-running runtimes (RoadRunner, FrankenPHP) and PSR integration.</li>
<li><strong><code>Presenter::getRequest()</code> throws instead of returning <code>null</code></strong> when the presenter isn't running yet</li>
<li><strong><code>LatteFactory::create()</code> now takes <code>?Control</code></strong> – update any custom <code>LatteFactory</code> implementation to the new <code>create(?Control $control = null)</code> signature.</li>
<li><strong>Removed <code>{ifCurrent}</code></strong> – use <code>{if isLinkCurrent('...')}</code>.</li>
<li><strong>Removed compatibility with old class names</strong> such as <code>PresenterComponent</code> and <code>IRouter</code>.</li>
</ul>
<h2><g-emoji class="g-emoji" alias="warning">⚠️</g-emoji> Deprecations</h2>
<p>Mostly very old curiosities that few people knew existed – they still work but now emit a deprecation notice:</p>
<ul>
<li><strong><code>@annotations</code> → PHP attributes</strong>: <code>@persistent</code> → <code>#[Persistent]</code>, <code>@crossOrigin</code> → <code>#[Requires(sameOrigin: false)]</code>, <code>@deprecated</code> → <code>#[Deprecated]</code>.</li>
<li><strong>Array access on <code>RouteList</code></strong> – <code>$router[] = new Route(...)</code> and friends are replaced by <code>$router-&gt;addRoute(...)</code> / <code>getRouters()</code>.</li>
<li><strong>Query string in a link destination</strong> – <code>link('Product:detail?id=1')</code> should pass arguments instead: <code>link('Product:detail', ['id' =&gt; 1])</code>.</li>
<li><strong><code>Component::getParameter()</code> second <code>$default</code> argument</strong> – use the <code>??</code> operator instead.</li>
<li><strong>Some magic properties</strong> (<code>$presenter-&gt;view</code>, <code>$layout</code>, <code>$request</code>, <code>$session</code>…) – use the getters.</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong>Set the URL fragment straight from arguments</strong> – <code>link('Product:detail', ['#' =&gt; 'reviews'])</code> produces <code>...#reviews</code>. The value is URL-encoded, must be scalar, and isn't passed on as a request parameter.</li>
<li><strong>New <code>Presenter::completeTemplate()</code></strong> – a <code>protected</code> method extracted from <code>sendTemplate()</code> that you can override to inject shared variables or set the template file before rendering.</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 24 Jun 2026 18:26:19 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/v3.3.0</guid>
	</item>
	<item>
		<title>Forms v3.3.0</title>
		<link>https://github.com/nette/forms/releases/tag/v3.3.0</link>
		<description>The headline of 3.3 is CSRF protection that the browser handles for you – no token, no cookie, no server-side state, and it holds even against XSS. On top of that, the confusing {formContext} / {formContainer} pair collapses into a single {form scope}, you can finally nest forms with {form detached}, and a round of housekeeping clears out long-deprecated APIs. Please test and report anything that breaks for you.

PHP 8.3+ and Latte 3.1.4+ are now required.

💥 Breaking Changes

CSRF is now strictly same-origin. Forms validate the Sec-Fetch-Site header instead of the old SameSite cookie. The previous mechanism trusted submissions from any subdomain of the same site; the new one demands an exact origin match (scheme + host + port).
setValues() / setDefaults() now expect iterable|stdClass.
RadioList / CheckboxList: getControlPart() and getLabelPart() throw on an invalid item key instead of silently returning a nonsensical result.
Removed long-deprecated APIs:** DataClassGenerator, LatteRenderer, getValues(true) (use getValues(&apos;array&apos;)), and the $default parameter of getOption() (use the ?? operator), negative validation rules

✨ New Features

{form scope name} – one tag to replace the easily-confused {formContext} and {formContainer}. It pushes the form onto the stack without emitting &lt;form&gt;, resolving the name relatively to an active form when there is one, otherwise from the top level.
{form detached name} – nest forms at last. HTML forbids nested &lt;form&gt; tags, so detached emits an empty &lt;form&gt;&lt;/form&gt; up front and links every control back to it via the HTML5 form=&quot;...&quot; attribute, no matter where they sit in the DOM.
addSubmit() accepts an $onSubmit callback – attach a click handler right when you create the button, without a separate -&gt;onClick[] =.

🗑️ Deprecations

A missing comma before {form} arguments – write {form name, attr=val} instead of {form name attr=val}, freeing keywords like scope/detached next to the name.
Several magic properties
</description>
		<content:encoded><![CDATA[
		<p>The headline of 3.3 is <strong>CSRF protection that the browser handles for you</strong> – no token, no cookie, no server-side state, and it holds even against XSS. On top of that, the confusing <code>{formContext}</code> / <code>{formContainer}</code> pair collapses into a single <code>{form scope}</code>, you can finally nest forms with <code>{form detached}</code>, and a round of housekeeping clears out long-deprecated APIs. Please test and report anything that breaks for you.</p>
<ul>
<li><strong>PHP 8.3+ and Latte 3.1.4+ are now required.</strong></li>
</ul>
<h2>💥 Breaking Changes</h2>
<ul>
<li><strong>CSRF is now strictly same-origin.</strong> Forms validate the <code>Sec-Fetch-Site</code> header instead of the old SameSite cookie. The previous mechanism trusted submissions from any subdomain of the same site; the new one demands an exact origin match (scheme + host + port).</li>
<li><code>setValues()</code> / <code>setDefaults()</code> now expect <code>iterable|stdClass</code>.</li>
<li><code>RadioList</code> / <code>CheckboxList</code>: <code>getControlPart()</code> and <code>getLabelPart()</code> throw on an invalid item key instead of silently returning a nonsensical result.</li>
<li>Removed long-deprecated APIs:** <code>DataClassGenerator</code>, <code>LatteRenderer</code>, <code>getValues(true)</code> (use <code>getValues('array')</code>), and the <code>$default</code> parameter of <code>getOption()</code> (use the <code>??</code> operator), negative validation rules</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong><code>{form scope name}</code></strong> – one tag to replace the easily-confused <code>{formContext}</code> and <code>{formContainer}</code>. It pushes the form onto the stack without emitting <code>&lt;form&gt;</code>, resolving the name relatively to an active form when there is one, otherwise from the top level.</li>
<li><strong><code>{form detached name}</code></strong> – nest forms at last. HTML forbids nested <code>&lt;form&gt;</code> tags, so <code>detached</code> emits an empty <code>&lt;form&gt;&lt;/form&gt;</code> up front and links every control back to it via the HTML5 <code>form="..."</code> attribute, no matter where they sit in the DOM.</li>
<li><strong><code>addSubmit()</code> accepts an <code>$onSubmit</code> callback</strong> – attach a click handler right when you create the button, without a separate <code>-&gt;onClick[] =</code>.</li>
</ul>
<h2>🗑️ Deprecations</h2>
<ul>
<li>A missing comma before <code>{form}</code> arguments – write <code>{form name, attr=val}</code> instead of <code>{form name attr=val}</code>, freeing keywords like <code>scope</code>/<code>detached</code> next to the name.</li>
<li>Several magic properties</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 24 Jun 2026 17:13:42 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/forms/releases/tag/v3.3.0</guid>
	</item>
	<item>
		<title>Component Model v4.0.0</title>
		<link>https://github.com/nette/component-model/releases/tag/v4.0.0</link>
		<description>A focused, modern major release. The component model drops legacy baggage, demands PHP 8.3+, and ships a smarter monitoring system that finally behaves predictably when listeners reshape the tree. If you&apos;ve been carrying around deprecated attached()/detached() hooks or the magic getComponents() parameters, this is your cue to clean up – the payoff is a leaner, stricter, more reliable foundation.
💥 Breaking Changes


Monitoring handlers now fire top-down (ancestor → descendant). When a subtree is attached, monitor() listeners are invoked from the outermost ancestor inward, matching the natural order of tree construction. The new implementation is robust against listeners that mutate the tree mid-flight: it re-checks validity before descending into children, deduplicates so the same listener never runs twice, and guards against reentry to prevent infinite loops. If your code relied on the old ordering, review listeners that depend on sibling or parent state.


attached() / detached() methods removed. These long-deprecated lifecycle hooks are gone. Migrate to explicit callbacks: replace overridden attached($obj) / detached($obj) with monitor($type, attached: ..., detached: ...). Calling monitor() with no handler at all now throws an InvalidStateException – at least one of attached or detached is required.


Container::getComponents() parameters removed. The method now takes no arguments and returns a plain array of immediate children (previously iterable). The old recursive flag and filter-type argument are gone – passing them throws a DeprecatedException. For recursive traversal use getComponentTree() instead. The internal RecursiveComponentIterator has been removed.


IContainer::addComponent() signature tightened. Now declared as addComponent(IComponent $component, ?string $name): static. Implementations and callers must match the new return type hint.


Nette\SmartObject dropped from Component. The component no longer pulls in the SmartObject trait, and the magic $name, $parent, and $components properties are gone. Use the explicit methods (getName(), getParent(), getComponents()) directly.


IComponent::NAME_SEPARATOR removed. Use IComponent::NameSeparator instead.


PHP 8.3 required.

</description>
		<content:encoded><![CDATA[
		<p>A focused, modern major release. The component model drops legacy baggage, demands PHP 8.3+, and ships a smarter monitoring system that finally behaves predictably when listeners reshape the tree. If you've been carrying around deprecated <code>attached()</code>/<code>detached()</code> hooks or the magic <code>getComponents()</code> parameters, this is your cue to clean up – the payoff is a leaner, stricter, more reliable foundation.</p>
<h2>💥 Breaking Changes</h2>
<ul>
<li>
<p><strong>Monitoring handlers now fire top-down (ancestor → descendant).</strong> When a subtree is attached, <code>monitor()</code> listeners are invoked from the outermost ancestor inward, matching the natural order of tree construction. The new implementation is robust against listeners that mutate the tree mid-flight: it re-checks validity before descending into children, deduplicates so the same listener never runs twice, and guards against reentry to prevent infinite loops. If your code relied on the old ordering, review listeners that depend on sibling or parent state.</p>
</li>
<li>
<p><strong><code>attached()</code> / <code>detached()</code> methods removed.</strong> These long-deprecated lifecycle hooks are gone. Migrate to explicit callbacks: replace overridden <code>attached($obj)</code> / <code>detached($obj)</code> with <code>monitor($type, attached: ..., detached: ...)</code>. Calling <code>monitor()</code> with no handler at all now throws an <code>InvalidStateException</code> – at least one of <code>attached</code> or <code>detached</code> is required.</p>
</li>
<li>
<p><strong><code>Container::getComponents()</code> parameters removed.</strong> The method now takes no arguments and returns a plain <code>array</code> of immediate children (previously <code>iterable</code>). The old recursive flag and filter-type argument are gone – passing them throws a <code>DeprecatedException</code>. For recursive traversal use <strong><code>getComponentTree()</code></strong> instead. The internal <code>RecursiveComponentIterator</code> has been removed.</p>
</li>
<li>
<p><strong><code>IContainer::addComponent()</code> signature tightened.</strong> Now declared as <code>addComponent(IComponent $component, ?string $name): static</code>. Implementations and callers must match the new return type hint.</p>
</li>
<li>
<p><strong><code>Nette\SmartObject</code> dropped from <code>Component</code>.</strong> The component no longer pulls in the <code>SmartObject</code> trait, and the magic <code>$name</code>, <code>$parent</code>, and <code>$components</code> properties are gone. Use the explicit methods (<code>getName()</code>, <code>getParent()</code>, <code>getComponents()</code>) directly.</p>
</li>
<li>
<p><strong><code>IComponent::NAME_SEPARATOR</code> removed.</strong> Use <code>IComponent::NameSeparator</code> instead.</p>
</li>
<li>
<p><strong>PHP 8.3 required.</strong></p>
</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 21 Jun 2026 23:34:40 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/component-model/releases/tag/v4.0.0</guid>
	</item>
	<item>
		<title>Bootstrap v3.3.0</title>
		<link>https://github.com/nette/bootstrap/releases/tag/v3.3.0</link>
		<description>A maintenance release that modernizes the foundations: Nette Bootstrap now targets PHP 8.3+ and the latest Nette stack. By dropping legacy compatibility shims, the codebase is leaner and fully covered by mandatory static analysis. Upgrading is mostly a matter of bringing your dependencies up to date.</description>
		<content:encoded><![CDATA[
		<p>A maintenance release that modernizes the foundations: Nette Bootstrap now targets PHP 8.3+ and the latest Nette stack. By dropping legacy compatibility shims, the codebase is leaner and fully covered by mandatory static analysis. Upgrading is mostly a matter of bringing your dependencies up to date.</p>
		]]></content:encoded>
		<pubDate>Sun, 21 Jun 2026 22:22:07 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/bootstrap/releases/tag/v3.3.0</guid>
	</item>
	<item>
		<title>Bootstrap v3.2.9</title>
		<link>https://github.com/nette/bootstrap/releases/tag/v3.2.9</link>
		<description>
Configurator: pass debugMode to MailExtension
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Configurator: pass debugMode to MailExtension</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 21 Jun 2026 22:03:46 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/bootstrap/releases/tag/v3.2.9</guid>
	</item>
	<item>
		<title>Security v3.2.5</title>
		<link>https://github.com/nette/security/releases/tag/v3.2.5</link>
		<description>
fixed compatibility with nette/http 3.4
Identity: use ctype_digit for stricter numeric ID detection
</description>
		<content:encoded><![CDATA[
		<ul>
<li>fixed compatibility with nette/http 3.4</li>
<li>Identity: use ctype_digit for stricter numeric ID detection</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 15 Jun 2026 05:44:10 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/security/releases/tag/v3.2.5</guid>
	</item>
	<item>
		<title>Http v3.4.0</title>
		<link>https://github.com/nette/http/releases/tag/v3.4.0</link>
		<description>This release brings serious firepower to server-side HTTP handling. The headline is a brand-new SSRF defense kit – IPAddress and UrlValidator let you validate URLs and pin connections before your app ever talks to an attacker-controlled host. On top of that, cookie handling gets a modern overhaul with a type-safe SameSite enum, CHIPS/Partitioned support, and a proper Max-Age attribute, while the new Request::isFrom() gives you reliable same-site request detection – even on Safari. Now on PHP 8.3.
Changes

PHP 8.3 is now required. Time to upgrade your runtime if you haven&apos;t already.
UserStorage is gone – the long-deprecated class has been removed. Use the standard authentication storage instead.
Request::getRemoteHost() is deprecated and now returns null – reverse DNS lookups were slow, unreliable, and a privacy footgun. Resolve the hostname yourself from getRemoteAddress() if you really need it (#218).

Deprecations (still working, but plan ahead)

The IResponse::SameSite* constants are deprecated in favor of the new SameSite enum.
Request::isSameSite() is deprecated – use isFrom() instead.
Passing integer 0 as the expiration to Response::setCookie() is deprecated – use null for a session cookie.

✨ New Features

SSRF protection, batteries included – the new IPAddress is an immutable IPv4/IPv6 value object with rich predicates (isPublic(), isPrivate(), isLoopback(), isLinkLocal(), isMulticast(), isReserved()), CIDR matching via isInRange(), and IPv4-mapped IPv6 normalization. Pair it with UrlValidator, a configurable guard that vets scheme, port, host allow/blocklists, userinfo, and – optionally with DNS – the resolved IP ranges. It even hands back the resolved IPs so you can pin the connection through CURLOPT_RESOLVE and defeat DNS-rebinding.
Request::isFrom() – a single, reliable way to check where a request came from, with site, dest, and user parameters built on the Sec-Fetch-* headers. For browsers without Sec-Fetch support (Safari &lt; 16.4), it transparently falls back to a strict cookie, so same-site detection just works everywhere.
Type-safe SameSite enum – setCookie() and Session now accept a proper enum instead of magic strings, so typos become compile-time problems, not silent security holes.
Response::setCookie() speaks modern cookie – it now supports the Partitioned attribute (CHIPS) for third-party cookies, emits a Max-Age attribute (which takes precedence over expires and ignores the client clock), and forces Secure automatically when SameSite=None, sparing you a browser rejection.
Helpers::expirationToSeconds() – one consistent parser for every expiration value across the library. Numbers are relative seconds, while DateTimeInterface and textual strings like &apos;20 minutes&apos; or &apos;2024-01-01&apos; resolve as absolute times; each caller decides what null means in its own context.
Helpers::parseQualityList() – parses HTTP quality-value lists (Accept, Accept-Language, …) into a ranked token map. Request::detectLanguage() was rewritten on top of it and is more correct as a result.
</description>
		<content:encoded><![CDATA[
		<p>This release brings serious firepower to server-side HTTP handling. The headline is a brand-new <strong>SSRF defense kit</strong> – <code>IPAddress</code> and <code>UrlValidator</code> let you validate URLs and pin connections before your app ever talks to an attacker-controlled host. On top of that, cookie handling gets a modern overhaul with a type-safe <code>SameSite</code> enum, CHIPS/<code>Partitioned</code> support, and a proper <code>Max-Age</code> attribute, while the new <code>Request::isFrom()</code> gives you reliable same-site request detection – even on Safari. Now on PHP 8.3.</p>
<h2>Changes</h2>
<ul>
<li><strong>PHP 8.3 is now required.</strong> Time to upgrade your runtime if you haven't already.</li>
<li><strong><code>UserStorage</code> is gone</strong> – the long-deprecated class has been removed. Use the standard authentication storage instead.</li>
<li><strong><code>Request::getRemoteHost()</code> is deprecated and now returns <code>null</code></strong> – reverse DNS lookups were slow, unreliable, and a privacy footgun. Resolve the hostname yourself from <code>getRemoteAddress()</code> if you really need it (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1438535664" data-permission-text="Title is private" data-url="https://github.com/nette/http/issues/218" data-hovercard-type="issue" data-hovercard-url="/nette/http/issues/218/hovercard" href="https://github.com/nette/http/issues/218">#218</a>).</li>
</ul>
<h3>Deprecations (still working, but plan ahead)</h3>
<ul>
<li>The <code>IResponse::SameSite*</code> constants are deprecated in favor of the new <code>SameSite</code> enum.</li>
<li><code>Request::isSameSite()</code> is deprecated – use <code>isFrom()</code> instead.</li>
<li>Passing integer <code>0</code> as the expiration to <code>Response::setCookie()</code> is deprecated – use <code>null</code> for a session cookie.</li>
</ul>
<h2>✨ New Features</h2>
<ul>
<li><strong>SSRF protection, batteries included</strong> – the new <strong>IPAddress</strong> is an immutable IPv4/IPv6 value object with rich predicates (<code>isPublic()</code>, <code>isPrivate()</code>, <code>isLoopback()</code>, <code>isLinkLocal()</code>, <code>isMulticast()</code>, <code>isReserved()</code>), CIDR matching via <code>isInRange()</code>, and IPv4-mapped IPv6 normalization. Pair it with <strong>UrlValidator</strong>, a configurable guard that vets scheme, port, host allow/blocklists, userinfo, and – optionally with DNS – the resolved IP ranges. It even hands back the resolved IPs so you can pin the connection through <code>CURLOPT_RESOLVE</code> and defeat DNS-rebinding.</li>
<li><strong><code>Request::isFrom()</code></strong> – a single, reliable way to check where a request came from, with <code>site</code>, <code>dest</code>, and <code>user</code> parameters built on the <code>Sec-Fetch-*</code> headers. For browsers without <code>Sec-Fetch</code> support (Safari &lt; 16.4), it transparently falls back to a strict cookie, so same-site detection just works everywhere.</li>
<li><strong>Type-safe <code>SameSite</code> enum</strong> – <code>setCookie()</code> and <code>Session</code> now accept a proper enum instead of magic strings, so typos become compile-time problems, not silent security holes.</li>
<li><strong><code>Response::setCookie()</code> speaks modern cookie</strong> – it now supports the <strong><code>Partitioned</code></strong> attribute (CHIPS) for third-party cookies, emits a <strong><code>Max-Age</code></strong> attribute (which takes precedence over <code>expires</code> and ignores the client clock), and <strong>forces <code>Secure</code> automatically when <code>SameSite=None</code></strong>, sparing you a browser rejection.</li>
<li><strong><code>Helpers::expirationToSeconds()</code></strong> – one consistent parser for every expiration value across the library. Numbers are relative seconds, while <code>DateTimeInterface</code> and textual strings like <code>'20 minutes'</code> or <code>'2024-01-01'</code> resolve as absolute times; each caller decides what <code>null</code> means in its own context.</li>
<li><strong><code>Helpers::parseQualityList()</code></strong> – parses HTTP quality-value lists (<code>Accept</code>, <code>Accept-Language</code>, …) into a ranked token map. <code>Request::detectLanguage()</code> was rewritten on top of it and is more correct as a result.</li>
</ul>
		]]></content:encoded>
		<pubDate>Sat, 13 Jun 2026 01:09:27 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/http/releases/tag/v3.4.0</guid>
	</item>
	<item>
		<title>Application v3.2.10</title>
		<link>https://github.com/nette/application/releases/tag/v3.2.10</link>
		<description>
Sharper phpDoc types and descriptions throughout the codebase
Reverted the experimental hasPresenter()/getPresenterIfExists() addition and the $throw deprecation in Component/Form::getPresenter() – the previous API behavior stays unchanged
{layout auto} no longer triggers infinite recursion – when used inside a referring template, the layout finder is now skipped instead of looping back on itself
Response and router classes now use promoted readonly properties, trimming boilerplate across Application, FileResponse, JsonResponse, RedirectResponse, TextResponse, ForwardResponse and CliRouter
Callback parameters in PresenterFactory, CallbackResponse and Multiplier are normalized to Closure for stronger typing
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Sharper phpDoc types and descriptions throughout the codebase</li>
<li>Reverted the experimental <code>hasPresenter()/getPresenterIfExists()</code> addition and the <code>$throw</code> deprecation in <code>Component</code>/<code>Form::getPresenter()</code> – the previous API behavior stays unchanged</li>
<li><strong>{layout auto}</strong> no longer triggers infinite recursion – when used inside a referring template, the layout finder is now skipped instead of looping back on itself</li>
<li>Response and router classes now use <strong>promoted readonly properties</strong>, trimming boilerplate across <code>Application</code>, <code>FileResponse</code>, <code>JsonResponse</code>, <code>RedirectResponse</code>, <code>TextResponse</code>, <code>ForwardResponse</code> and <code>CliRouter</code></li>
<li>Callback parameters in <code>PresenterFactory</code>, <code>CallbackResponse</code> and <code>Multiplier</code> are normalized to <strong><code>Closure</code></strong> for stronger typing</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 01 Jun 2026 18:34:36 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/v3.2.10</guid>
	</item>
	<item>
		<title>Http v3.3.4</title>
		<link>https://github.com/nette/http/releases/tag/v3.3.4</link>
		<description>
RequestFactory::setForceHttps() – force the request scheme to HTTPS regardless of the server environment, handy behind proxies and load balancers that don&apos;t advertise TLS termination. Also exposed via the DI config option http: forceHttps: true.
Request::getOrigin() now strictly follows RFC 6454 – returns null for any Origin header that isn&apos;t a bare scheme://host[:port] (e.g. headers containing a path are rejected instead of being silently accepted).
Improved phpDoc types and descriptions across the whole Nette\Http namespace – better IDE autocompletion and PHPStan inference for Request, Response, Session, Url and friends.
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>RequestFactory::setForceHttps()</strong> – force the request scheme to HTTPS regardless of the server environment, handy behind proxies and load balancers that don't advertise TLS termination. Also exposed via the DI config option <code>http: forceHttps: true</code>.</li>
<li><strong>Request::getOrigin()</strong> now strictly follows RFC 6454 – returns <code>null</code> for any <code>Origin</code> header that isn't a bare <code>scheme://host[:port]</code> (e.g. headers containing a path are rejected instead of being silently accepted).</li>
<li>Improved phpDoc types and descriptions across the whole <code>Nette\Http</code> namespace – better IDE autocompletion and PHPStan inference for <code>Request</code>, <code>Response</code>, <code>Session</code>, <code>Url</code> and friends.</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 26 May 2026 16:58:49 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/http/releases/tag/v3.3.4</guid>
	</item>
	<item>
		<title>Forms v3.2.9</title>
		<link>https://github.com/nette/forms/releases/tag/v3.2.9</link>
		<description>A maintenance-focused release that tightens type safety across the whole codebase, modernizes the JavaScript test stack, and turns static analysis into a non-negotiable part of the build. No API changes – just a more solid foundation under the hood.

Native types everywhere – filled in missing native type declarations across Container, BaseControl, Validator, Rules, Form and friends, so PHPStan (and your IDE) see the real shape of things
Sharper phpDoc – tightened phpDoc types and descriptions throughout, giving better autocomplete and clearer intent at every call - Reorganized a few tests and switched some over to allowCrossOrigin() for clarity
</description>
		<content:encoded><![CDATA[
		<p>A maintenance-focused release that tightens type safety across the whole codebase, modernizes the JavaScript test stack, and turns static analysis into a non-negotiable part of the build. No API changes – just a more solid foundation under the hood.</p>
<ul>
<li><strong>Native types everywhere</strong> – filled in missing native type declarations across <code>Container</code>, <code>BaseControl</code>, <code>Validator</code>, <code>Rules</code>, <code>Form</code> and friends, so PHPStan (and your IDE) see the real shape of things</li>
<li><strong>Sharper phpDoc</strong> – tightened phpDoc types and descriptions throughout, giving better autocomplete and clearer intent at every call - Reorganized a few tests and switched some over to <code>allowCrossOrigin()</code> for clarity</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 26 May 2026 12:17:13 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/forms/releases/tag/v3.2.9</guid>
	</item>
	<item>
		<title>Component Model v3.2.0</title>
		<link>https://github.com/nette/component-model/releases/tag/v3.2.0</link>
		<description>A transitional release ahead of 4.0. Nothing is removed yet, this version just lights up deprecation notices on things that will disappear in 4.0, so you can get your code ready in peace.
💥 Deprecated (will be removed in 4.0)

Magic properties Component::$name, Component::$parent and Container::$components – use getName(), getParent(), getComponents() instead.
Calling monitor($type) without callbacks – pass them directly: monitor($type, $attached, $detached). Overriding attached() / detached() in subclasses is on its way out.
Constant IComponent::NAME_SEPARATOR – switch to IComponent::NameSeparator (the deprecation is now reported via the native #[\Deprecated] attribute).
</description>
		<content:encoded><![CDATA[
		<p>A transitional release ahead of 4.0. Nothing is removed yet, this version just lights up deprecation notices on things that will disappear in 4.0, so you can get your code ready in peace.</p>
<h2>💥 Deprecated (will be removed in 4.0)</h2>
<ul>
<li>Magic properties <code>Component::$name</code>, <code>Component::$parent</code> and <code>Container::$components</code> – use <code>getName()</code>, <code>getParent()</code>, <code>getComponents()</code> instead.</li>
<li>Calling <code>monitor($type)</code> without callbacks – pass them directly: <code>monitor($type, $attached, $detached)</code>. Overriding <code>attached()</code> / <code>detached()</code> in subclasses is on its way out.</li>
<li>Constant <code>IComponent::NAME_SEPARATOR</code> – switch to <code>IComponent::NameSeparator</code> (the deprecation is now reported via the native <code>#[\Deprecated]</code> attribute).</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 26 May 2026 10:39:52 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/component-model/releases/tag/v3.2.0</guid>
	</item>
	<item>
		<title>Mail v4.1.2</title>
		<link>https://github.com/nette/mail/releases/tag/v4.1.2</link>
		<description>
Interceptor – a new mailer wrapper that redirects all outgoing To/Cc/Bcc (plus read-receipt headers) to one fixed address, preserves the originals in X-Original-* headers, and optionally adds a subject prefix. No more sending test mail to real customers by accident. Wire it via DI with mail.redirect: dev@example.com and it slots in automatically.
MailTracy Bar panel – a new Bridges/MailTracy/MailPanel subscribes to Interceptor::$onSent and lists each sent message (From / To+Cc+Bcc / Subject / Status) right in the Tracy Bar. Auto-registers in debug mode whenever the Interceptor is active; opt in or out explicitly with mail: debugger: true|false.
HtmlComposer – a standalone HTML pre-processing pipeline you can drive directly: opt in to inlineCss() (accumulates stylesheets across calls), embedImages($basePath), and let it handle &lt;title&gt; to subject extraction and plain-text alternative generation. Message::setHtmlBody() keeps working as a BC-friendly facade.
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>Interceptor</strong> – a new mailer wrapper that redirects all outgoing <code>To</code>/<code>Cc</code>/<code>Bcc</code> (plus read-receipt headers) to one fixed address, preserves the originals in <code>X-Original-*</code> headers, and optionally adds a subject prefix. No more sending test mail to real customers by accident. Wire it via DI with <code>mail.redirect: dev@example.com</code> and it slots in automatically.</li>
<li><strong>MailTracy Bar panel</strong> – a new <code>Bridges/MailTracy/MailPanel</code> subscribes to <code>Interceptor::$onSent</code> and lists each sent message (From / To+Cc+Bcc / Subject / Status) right in the Tracy Bar. Auto-registers in debug mode whenever the Interceptor is active; opt in or out explicitly with <code>mail: debugger: true|false</code>.</li>
<li><strong><code>HtmlComposer</code></strong> – a standalone HTML pre-processing pipeline you can drive directly: opt in to <code>inlineCss()</code> (accumulates stylesheets across calls), <code>embedImages($basePath)</code>, and let it handle <code>&lt;title&gt;</code> to subject extraction and plain-text alternative generation. <code>Message::setHtmlBody()</code> keeps working as a BC-friendly facade.</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 19 May 2026 17:58:24 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/mail/releases/tag/v4.1.2</guid>
	</item>
	<item>
		<title>Caching v3.4.2</title>
		<link>https://github.com/nette/caching/releases/tag/v3.4.2</link>
		<description>A housekeeping release focused on code quality: every class and method now carries clearer, more descriptive PHPDoc, type hints got sharper (both native and annotated), and static analysis is now a mandatory part of CI with the official Nette PHPStan rules. No API changes – just a tidier, better-typed codebase.</description>
		<content:encoded><![CDATA[
		<p>A housekeeping release focused on code quality: every class and method now carries clearer, more descriptive PHPDoc, type hints got sharper (both native and annotated), and static analysis is now a mandatory part of CI with the official Nette PHPStan rules. No API changes – just a tidier, better-typed codebase.</p>
		]]></content:encoded>
		<pubDate>Tue, 12 May 2026 01:33:41 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/caching/releases/tag/v3.4.2</guid>
	</item>
	<item>
		<title>Neon v3.4.8</title>
		<link>https://github.com/nette/neon/releases/tag/v3.4.8</link>
		<description>
More precise phpDoc types across the codebase – better autocompletion and stricter static analysis
Improved phpDoc descriptions for the public API
</description>
		<content:encoded><![CDATA[
		<ul>
<li>More precise phpDoc types across the codebase – better autocompletion and stricter static analysis</li>
<li>Improved phpDoc descriptions for the public API</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 11 May 2026 21:43:26 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/neon/releases/tag/v3.4.8</guid>
	</item>
	<item>
		<title>Security v3.2.3</title>
		<link>https://github.com/nette/security/releases/tag/v3.2.3</link>
		<description>A small maintenance release headlined by a fix to session-based identity storage, plus a tightening of the project&apos;s static analysis setup and a round of phpDoc polish.

SessionStorage no longer refreshes the sliding expiration timestamp once the session has already expired – an expired identity stays expired instead of being silently kept alive for another round
Adopted nette/phpstan-rules and made static analysis a mandatory part of the build, then resolved the errors it surfaced
Improved phpDoc types and descriptions across the codebase
</description>
		<content:encoded><![CDATA[
		<p>A small maintenance release headlined by a fix to session-based identity storage, plus a tightening of the project's static analysis setup and a round of phpDoc polish.</p>
<ul>
<li><strong>SessionStorage</strong> no longer refreshes the sliding expiration timestamp once the session has already expired – an expired identity stays expired instead of being silently kept alive for another round</li>
<li>Adopted <code>nette/phpstan-rules</code> and made static analysis a mandatory part of the build, then resolved the errors it surfaced</li>
<li>Improved phpDoc types and descriptions across the codebase</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 11 May 2026 21:19:01 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/security/releases/tag/v3.2.3</guid>
	</item>
	<item>
		<title>Security v3.2.4</title>
		<link>https://github.com/nette/security/releases/tag/v3.2.4</link>
		<description>

Guest identity – an IdentityHandler authenticator may now implement getGuestIdentity(): ?IIdentity to hand anonymous visitors a real identity. When present, getIdentity(), getId() and getRoles() transparently fall back to it, so guests carry their own roles and data instead of just the $guestRole string. The guest identity is resolved on read only and never written to storage.


$persistIdentity – the new User::$persistIdentity property lets you decide what happens to the identity after logout or expiration. It stays available for personalization by default; flip it to false and getIdentity()/getId() return null once the user is no longer logged in. Configurable straight from the security.authentication DI section.


SessionStorage no longer refreshes the sliding expiration timestamp once the session has already expired – an expired identity stays expired instead of being silently kept alive for another round


Adopted nette/phpstan-rules and made static analysis a mandatory part of the build, then resolved the errors it surfaced


Improved phpDoc types and descriptions across the codebase

</description>
		<content:encoded><![CDATA[
		<ul>
<li>
<p><strong>Guest identity</strong> – an <code>IdentityHandler</code> authenticator may now implement <code>getGuestIdentity(): ?IIdentity</code> to hand anonymous visitors a real identity. When present, <code>getIdentity()</code>, <code>getId()</code> and <code>getRoles()</code> transparently fall back to it, so guests carry their own roles and data instead of just the <code>$guestRole</code> string. The guest identity is resolved on read only and never written to storage.</p>
</li>
<li>
<p><strong>$persistIdentity</strong> – the new <code>User::$persistIdentity</code> property lets you decide what happens to the identity after logout or expiration. It stays available for personalization by default; flip it to <code>false</code> and <code>getIdentity()</code>/<code>getId()</code> return <code>null</code> once the user is no longer logged in. Configurable straight from the <code>security.authentication</code> DI section.</p>
</li>
<li>
<p><strong>SessionStorage</strong> no longer refreshes the sliding expiration timestamp once the session has already expired – an expired identity stays expired instead of being silently kept alive for another round</p>
</li>
<li>
<p>Adopted <code>nette/phpstan-rules</code> and made static analysis a mandatory part of the build, then resolved the errors it surfaced</p>
</li>
<li>
<p>Improved phpDoc types and descriptions across the codebase</p>
</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 11 May 2026 21:19:01 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/security/releases/tag/v3.2.4</guid>
	</item>
	<item>
		<title>Utils v4.1.4</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.4</link>
		<description>
Process – a new class for starting and controlling external processes: read their output, feed them input, pipe one process into another, wait for completion, terminate, and check exit codes. Process::runExecutable() passes arguments as an array so there&apos;s zero shell involvement and no risk of shell injection, while Process::runCommand() is there when you really do want the shell. Comes with timeouts, incremental output consumption (consumeStdOutput() / consumeStdError()), and works on Windows too.
FileSystem::isValidFilename() – quickly check whether a string is a safe, cross-platform filename: it rejects path separators, control and reserved characters, trailing dots or spaces, and Windows device names like CON or LPT1.
Image::fromFile() and Image::fromString() now accept an optional $warnings parameter – pass it in and any GD warnings are handed back to you as a string instead of being emitted as a PHP warning, so you can log or display them on your own terms.
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>Process</strong> – a new class for starting and controlling external processes: read their output, feed them input, pipe one process into another, wait for completion, terminate, and check exit codes. <code>Process::runExecutable()</code> passes arguments as an array so there's zero shell involvement and no risk of shell injection, while <code>Process::runCommand()</code> is there when you really do want the shell. Comes with timeouts, incremental output consumption (<code>consumeStdOutput()</code> / <code>consumeStdError()</code>), and works on Windows too.</li>
<li><strong>FileSystem::isValidFilename()</strong> – quickly check whether a string is a safe, cross-platform filename: it rejects path separators, control and reserved characters, trailing dots or spaces, and Windows device names like <code>CON</code> or <code>LPT1</code>.</li>
<li><strong>Image::fromFile()</strong> and <strong>Image::fromString()</strong> now accept an optional <code>$warnings</code> parameter – pass it in and any GD warnings are handed back to you as a string instead of being emitted as a PHP warning, so you can log or display them on your own terms.</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 11 May 2026 20:59:10 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.4</guid>
	</item>
	<item>
		<title>Tester v2.6.1</title>
		<link>https://github.com/nette/tester/releases/tag/v2.6.1</link>
		<description>
PhpInterpreter now passes the command to proc_open() as an array, so PHP handles argument escaping itself and the subshell is bypassed on Linux too – fewer surprises with paths and arguments containing spaces or special characters
Test::getResult() throws a LogicException instead of silently returning an unset value when the test hasn&apos;t finished running yet – mistakes surface immediately rather than turning into puzzling downstream errors
Improved PHPDoc types and descriptions throughout the framework for better IDE hints and static analysis
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>PhpInterpreter</strong> now passes the command to <code>proc_open()</code> as an array, so PHP handles argument escaping itself and the subshell is bypassed on Linux too – fewer surprises with paths and arguments containing spaces or special characters</li>
<li><strong>Test::getResult()</strong> throws a <code>LogicException</code> instead of silently returning an unset value when the test hasn't finished running yet – mistakes surface immediately rather than turning into puzzling downstream errors</li>
<li>Improved PHPDoc types and descriptions throughout the framework for better IDE hints and static analysis</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 11 May 2026 18:21:48 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tester/releases/tag/v2.6.1</guid>
	</item>
	<item>
		<title>Di v3.2.6</title>
		<link>https://github.com/nette/di/releases/tag/v3.2.6</link>
		<description>A maintenance release laser-focused on type safety. Static analysis is now mandatory in CI, the codebase ships richer native and PHPDoc types, and the Tracy DI panel got a cleaner Latte rewrite. No behavioral changes – just a sturdier foundation for everything built on top.

Native types – tightened parameter and return types across Compiler, ContainerLoader, ServiceDefinition and friends
ContainerPanel – Tracy panel template rewritten with n:attributes for noticeably cleaner Latte syntax
PHPStan-clean codebase – wide-ranging cleanup across DI internals so the whole tree passes strict analysis
Richer PHPDoc – improved @param, @return and class descriptions across Compiler, Container, ContainerBuilder, Resolver, Helpers, definitions and extensions, giving IDEs and static analyzers far more to work with
Better generic types – sharpened PHPDoc generics in autowiring, container builder, definitions and resolver
</description>
		<content:encoded><![CDATA[
		<p>A maintenance release laser-focused on type safety. Static analysis is now mandatory in CI, the codebase ships richer native and PHPDoc types, and the Tracy DI panel got a cleaner Latte rewrite. No behavioral changes – just a sturdier foundation for everything built on top.</p>
<ul>
<li><strong>Native types</strong> – tightened parameter and return types across <code>Compiler</code>, <code>ContainerLoader</code>, <code>ServiceDefinition</code> and friends</li>
<li><strong>ContainerPanel</strong> – Tracy panel template rewritten with <code>n:attributes</code> for noticeably cleaner Latte syntax</li>
<li><strong>PHPStan-clean codebase</strong> – wide-ranging cleanup across DI internals so the whole tree passes strict analysis</li>
<li><strong>Richer PHPDoc</strong> – improved <code>@param</code>, <code>@return</code> and class descriptions across <code>Compiler</code>, <code>Container</code>, <code>ContainerBuilder</code>, <code>Resolver</code>, <code>Helpers</code>, definitions and extensions, giving IDEs and static analyzers far more to work with</li>
<li><strong>Better generic types</strong> – sharpened PHPDoc generics in autowiring, container builder, definitions and resolver</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 06 May 2026 01:46:54 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/di/releases/tag/v3.2.6</guid>
	</item>
	<item>
		<title>Component Model v3.1.4</title>
		<link>https://github.com/nette/component-model/releases/tag/v3.1.4</link>
		<description>A focused maintenance release for the Component layer. The headline is hardening of the monitor callback machinery: nested re-entry is now safely guarded, callbacks are normalized to \Closure for consistent deduplication, and the whole codebase has been brought under mandatory static analysis with nette/phpstan-rules.

Reentry protection for monitor callbacks – Component::refreshMonitors() now refuses to re-enter itself while listeners are running. If a listener removes and re-adds the same component (or otherwise triggers another refresh), each component is processed exactly once instead of looping or double-firing.
Reliable callback deduplication – switched the in-array check for monitor callbacks to loose comparison. Closures are never === to each other unless they are literally the same instance, so the previous strict check silently let duplicates through.
Adopted nette/phpstan-rules – stricter ruleset enabled, with a dedicated tests/types/component-types.php driving type tests.
</description>
		<content:encoded><![CDATA[
		<p>A focused maintenance release for the Component layer. The headline is hardening of the monitor callback machinery: nested re-entry is now safely guarded, callbacks are normalized to <code>\Closure</code> for consistent deduplication, and the whole codebase has been brought under mandatory static analysis with <code>nette/phpstan-rules</code>.</p>
<ul>
<li><strong>Reentry protection for monitor callbacks</strong> – <code>Component::refreshMonitors()</code> now refuses to re-enter itself while listeners are running. If a listener removes and re-adds the same component (or otherwise triggers another refresh), each component is processed exactly once instead of looping or double-firing.</li>
<li><strong>Reliable callback deduplication</strong> – switched the in-array check for monitor callbacks to loose comparison. Closures are never <code>===</code> to each other unless they are literally the same instance, so the previous strict check silently let duplicates through.</li>
<li><strong>Adopted <code>nette/phpstan-rules</code></strong> – stricter ruleset enabled, with a dedicated <code>tests/types/component-types.php</code> driving type tests.</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 06 May 2026 01:07:58 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/component-model/releases/tag/v3.1.4</guid>
	</item>
	<item>
		<title>Bootstrap v3.2.8</title>
		<link>https://github.com/nette/bootstrap/releases/tag/v3.2.8</link>
		<description>
Default parameters are now overridable in user configs – previously wwwDir: %rootDir%/www in common.neon was silently overwritten because defaults were injected after user configs.
%baseUrl% no longer crashes when HttpExtension is missing – the parameter is now a lazy statement resolved at runtime instead of a hard reference at compile time (#75).
Improved PHPDoc descriptions and types across the codebase.
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>Default parameters are now overridable in user configs</strong> – previously <code>wwwDir: %rootDir%/www</code> in <code>common.neon</code> was silently overwritten because defaults were injected <em>after</em> user configs.</li>
<li><strong><code>%baseUrl%</code> no longer crashes when <code>HttpExtension</code> is missing</strong> – the parameter is now a lazy statement resolved at runtime instead of a hard reference at compile time (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3382528776" data-permission-text="Title is private" data-url="https://github.com/nette/bootstrap/issues/75" data-hovercard-type="issue" data-hovercard-url="/nette/bootstrap/issues/75/hovercard" href="https://github.com/nette/bootstrap/issues/75">#75</a>).</li>
<li>Improved PHPDoc descriptions and types across the codebase.</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 05 May 2026 21:32:56 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/bootstrap/releases/tag/v3.2.8</guid>
	</item>
	<item>
		<title>Tracy v2.12.0</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.12.0</link>
		<description>Tracy learns to speak AI. This release turns every error screen, debug bar, and dump() call into a first-class citizen of agentic workflows – when an AI coding assistant hits your app, it gets a structured, token-efficient view of exactly what went wrong instead of a blob of HTML. Plus the usual spit-and-polish: a unified &quot;transparent frames&quot; model across BlueScreen and Dumper, a new breadcrumb in logged exceptions showing where Debugger::log() was called from, and a few quality-of-life API additions.
✨ New Features

AI agent support – Tracy now detects AI agents (via Helpers::isAgent()) and serves them tailored output instead of HTML:

BlueScreen renders a dedicated agent template for exceptions, making stack traces and context machine-readable
Debug Bar ships an agent-friendly render path with bespoke templates for the Warnings and Dumps panels
Debugger::dump() writes to the console when an agent is on the other end, so your dumps land where the agent actually looks
Production error page now includes a hint for agents so they don&apos;t have to guess what happened behind the generic 500


Markdown companion files – every HTML error log now gets a .md sibling, giving agents a clean, readable version of the same crash
Debugger::$transparentPaths – a public, autodetected list of &quot;framework&quot; paths (Tracy, Nette, Latte) whose frames are skipped when locating the real call site. Path-based, so it catches anonymous functions and closures that class-based detection missed
Helpers::findCallerLocation() – walks the backtrace and returns the first frame outside $transparentPaths, respecting @tracySkipLocation and internal functions. Reusable across Tracy instead of buried in Dumper
Helpers::countTransparentFrames() – companion helper returning the number of leading transparent frames in a trace
Logger records caller location – exception reports now show a &quot;Logged from ...&quot; footer pointing to the exact line where Debugger::log() was called, alongside the existing &quot;Report generated at&quot; entry
Dumper::toText() – gained an optional $key parameter so you can label the dumped value in text output

♻️ Code Refactoring

BlueScreen stack-trace collapse unified with Debugger::$transparentPaths – one source of truth for which frames to hide, replacing the inline logic in section-stack-exception.php. BlueScreen::$collapsePaths and isCollapsed() remain as @deprecated shims so existing configuration keeps working
BlueScreen internals cleaned up, including a new prepareStack(\Throwable) method that strips Tracy&apos;s own handler frames and returns the frame index to expand by default
</description>
		<content:encoded><![CDATA[
		<p>Tracy learns to speak AI. This release turns every error screen, debug bar, and <code>dump()</code> call into a first-class citizen of agentic workflows – when an AI coding assistant hits your app, it gets a structured, token-efficient view of exactly what went wrong instead of a blob of HTML. Plus the usual spit-and-polish: a unified "transparent frames" model across BlueScreen and Dumper, a new breadcrumb in logged exceptions showing where <code>Debugger::log()</code> was called from, and a few quality-of-life API additions.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>AI agent support</strong> – Tracy now detects AI agents (via Helpers::isAgent()) and serves them tailored output instead of HTML:
<ul>
<li><strong>BlueScreen</strong> renders a dedicated agent template for exceptions, making stack traces and context machine-readable</li>
<li><strong>Debug Bar</strong> ships an agent-friendly render path with bespoke templates for the Warnings and Dumps panels</li>
<li><strong>Debugger::dump()</strong> writes to the console when an agent is on the other end, so your dumps land where the agent actually looks</li>
<li><strong>Production error page</strong> now includes a hint for agents so they don't have to guess what happened behind the generic 500</li>
</ul>
</li>
<li><strong>Markdown companion files</strong> – every HTML error log now gets a <code>.md</code> sibling, giving agents a clean, readable version of the same crash</li>
<li><strong>Debugger::$transparentPaths</strong> – a public, autodetected list of "framework" paths (Tracy, Nette, Latte) whose frames are skipped when locating the real call site. Path-based, so it catches anonymous functions and closures that class-based detection missed</li>
<li><strong>Helpers::findCallerLocation()</strong> – walks the backtrace and returns the first frame outside <code>$transparentPaths</code>, respecting <code>@tracySkipLocation</code> and internal functions. Reusable across Tracy instead of buried in Dumper</li>
<li><strong>Helpers::countTransparentFrames()</strong> – companion helper returning the number of leading transparent frames in a trace</li>
<li><strong>Logger records caller location</strong> – exception reports now show a "Logged from ..." footer pointing to the exact line where <code>Debugger::log()</code> was called, alongside the existing "Report generated at" entry</li>
<li><strong>Dumper::toText()</strong> – gained an optional <code>$key</code> parameter so you can label the dumped value in text output</li>
</ul>
<h2>♻️ Code Refactoring</h2>
<ul>
<li><strong>BlueScreen stack-trace collapse</strong> unified with <code>Debugger::$transparentPaths</code> – one source of truth for which frames to hide, replacing the inline logic in <code>section-stack-exception.php</code>. <code>BlueScreen::$collapsePaths</code> and <code>isCollapsed()</code> remain as <code>@deprecated</code> shims so existing configuration keeps working</li>
<li><strong>BlueScreen</strong> internals cleaned up, including a new <code>prepareStack(\Throwable)</code> method that strips Tracy's own handler frames and returns the frame index to expand by default</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 04 May 2026 00:28:31 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.12.0</guid>
	</item>
	<item>
		<title>Mail v4.1.1</title>
		<link>https://github.com/nette/mail/releases/tag/v4.1.1</link>
		<description>🐛 Bug Fixes

Message::setHtmlBody() – survives large inline data: URIs. A &gt;500 kB base64 payload used to exhaust PCRE&apos;s backtrack limit and abort the whole send; the regex is now backtracking-free (#79)
Message::setHtmlBody() – embeds images whose quoted src=&quot;…&quot; or url(&apos;…&apos;) contains spaces, like &quot;holiday photos/beach.jpg&quot; (#97)
Message::setHtmlBody() – embeds images whose quoted path contains parentheses, so the classic screenshot (1).png naming no longer silently breaks (#89)
SendmailMailer – signs the full message so DKIM now covers Subject and To headers, closing a deliverability gap at Gmail, Outlook, and other strict providers (#99)
MimePart – quotes address phrases containing special characters before MIME-encoding, producing spec-compliant headers even when names include commas, angle brackets, or quotes (#102)
CssInliner – gracefully skips selectors the DOM engine can&apos;t evaluate; pseudo-classes and pseudo-elements like ::marker, :hover, :checked no longer break inlining
CssInliner – tokenizer regex fixed for very long strings and invalid url() quote combinations that previously tripped the parser
</description>
		<content:encoded><![CDATA[
		<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Message::setHtmlBody()</strong> – survives large inline <code>data:</code> URIs. A &gt;500 kB base64 payload used to exhaust PCRE's backtrack limit and abort the whole send; the regex is now backtracking-free (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="775323261" data-permission-text="Title is private" data-url="https://github.com/nette/mail/issues/79" data-hovercard-type="issue" data-hovercard-url="/nette/mail/issues/79/hovercard" href="https://github.com/nette/mail/issues/79">#79</a>)</li>
<li><strong>Message::setHtmlBody()</strong> – embeds images whose quoted <code>src="…"</code> or <code>url('…')</code> contains spaces, like <code>"holiday photos/beach.jpg"</code> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2088766719" data-permission-text="Title is private" data-url="https://github.com/nette/mail/issues/97" data-hovercard-type="issue" data-hovercard-url="/nette/mail/issues/97/hovercard" href="https://github.com/nette/mail/issues/97">#97</a>)</li>
<li><strong>Message::setHtmlBody()</strong> – embeds images whose quoted path contains parentheses, so the classic <code>screenshot (1).png</code> naming no longer silently breaks (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1320705520" data-permission-text="Title is private" data-url="https://github.com/nette/mail/issues/89" data-hovercard-type="issue" data-hovercard-url="/nette/mail/issues/89/hovercard" href="https://github.com/nette/mail/issues/89">#89</a>)</li>
<li><strong>SendmailMailer</strong> – signs the full message so DKIM now covers <code>Subject</code> and <code>To</code> headers, closing a deliverability gap at Gmail, Outlook, and other strict providers (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2255162594" data-permission-text="Title is private" data-url="https://github.com/nette/mail/issues/99" data-hovercard-type="issue" data-hovercard-url="/nette/mail/issues/99/hovercard" href="https://github.com/nette/mail/issues/99">#99</a>)</li>
<li><strong>MimePart</strong> – quotes address phrases containing special characters before MIME-encoding, producing spec-compliant headers even when names include commas, angle brackets, or quotes (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2578128385" data-permission-text="Title is private" data-url="https://github.com/nette/mail/issues/102" data-hovercard-type="pull_request" data-hovercard-url="/nette/mail/pull/102/hovercard" href="https://github.com/nette/mail/pull/102">#102</a>)</li>
<li><strong>CssInliner</strong> – gracefully skips selectors the DOM engine can't evaluate; pseudo-classes and pseudo-elements like <code>::marker</code>, <code>:hover</code>, <code>:checked</code> no longer break inlining</li>
<li><strong>CssInliner</strong> – tokenizer regex fixed for very long strings and invalid <code>url()</code> quote combinations that previously tripped the parser</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 23 Apr 2026 22:32:00 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/mail/releases/tag/v4.1.1</guid>
	</item>
	<item>
		<title>Latte v3.1.4</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.4</link>
		<description>
Range – a new Latte\Compiler\Range class (extending Position with a length) gives every token and parser node a precise source span instead of just a starting position, unlocking richer tooling and editor integrations
StatementNode::$tagRanges – statement nodes now expose exact byte ranges for their opening and closing tags, making it straightforward to map compiled output back to the original template
|limit accepts strings – the |limit filter now works on strings too, so you can trim text the same way you slice arrays
{dedent} – fixed inline content handling and atLineStart tracking; the logic moved into a dedicated Dedent class with considerably more test coverage (#412, #413, #414)
PhpHelpers::checkCode() – proc_open now uses array syntax for the PHP binary path, so installations where the interpreter lives in a directory with spaces no longer break (#415)
TemplateGenerator – stopped emitting the /** source */  comment for multi-line template names, which could produce broken PHP
{switch} – a {case} with a single value now compiles to === instead of in_array(), producing faster and cleaner generated PHP
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>Range</strong> – a new <code>Latte\Compiler\Range</code> class (extending <code>Position</code> with a <code>length</code>) gives every token and parser node a precise source span instead of just a starting position, unlocking richer tooling and editor integrations</li>
<li><strong>StatementNode::$tagRanges</strong> – statement nodes now expose exact byte ranges for their opening and closing tags, making it straightforward to map compiled output back to the original template</li>
<li><strong><code>|limit</code> accepts strings</strong> – the <code>|limit</code> filter now works on strings too, so you can trim text the same way you slice arrays</li>
<li><strong><code>{dedent}</code></strong> – fixed inline content handling and <code>atLineStart</code> tracking; the logic moved into a dedicated <code>Dedent</code> class with considerably more test coverage (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4133019498" data-permission-text="Title is private" data-url="https://github.com/nette/latte/issues/412" data-hovercard-type="issue" data-hovercard-url="/nette/latte/issues/412/hovercard" href="https://github.com/nette/latte/issues/412">#412</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4133242494" data-permission-text="Title is private" data-url="https://github.com/nette/latte/issues/413" data-hovercard-type="issue" data-hovercard-url="/nette/latte/issues/413/hovercard" href="https://github.com/nette/latte/issues/413">#413</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4204623353" data-permission-text="Title is private" data-url="https://github.com/nette/latte/issues/414" data-hovercard-type="pull_request" data-hovercard-url="/nette/latte/pull/414/hovercard" href="https://github.com/nette/latte/pull/414">#414</a>)</li>
<li><strong><code>PhpHelpers::checkCode()</code></strong> – <code>proc_open</code> now uses array syntax for the PHP binary path, so installations where the interpreter lives in a directory with spaces no longer break (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4232958618" data-permission-text="Title is private" data-url="https://github.com/nette/latte/issues/415" data-hovercard-type="pull_request" data-hovercard-url="/nette/latte/pull/415/hovercard" href="https://github.com/nette/latte/pull/415">#415</a>)</li>
<li><strong>TemplateGenerator</strong> – stopped emitting the <code>/** source */ </code> comment for multi-line template names, which could produce broken PHP</li>
<li><strong><code>{switch}</code></strong> – a <code>{case}</code> with a single value now compiles to <code>===</code> instead of <code>in_array()</code>, producing faster and cleaner generated PHP</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 23 Apr 2026 06:05:58 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.4</guid>
	</item>
	<item>
		<title>Tracy v2.11.4</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.11.4</link>
		<description>A maintenance release focused on CSP-friendly assets, mobile-friendly error pages, and a couple of handy API additions. Expect cleaner nonce handling, better behavior on phones, and a bar.js that no longer trips strict Content Security Policies.

script-src-elem support in Helpers::getNonce() – nonces are now also picked up from the script-src-elem CSP directive, not just script-src (#612).
CSP-friendly Tracy Bar – replaced the inline onload attribute in bar.js with a native addEventListener, eliminating a common CSP violation (#614).
FileSession::clean() – emits a warning when the session directory is not readable, making misconfigured storage easier to diagnose (#538).
Mobile-friendly error pages – BlueScreen and the 500 error template now include a proper viewport meta tag, so exceptions no longer render microscopically on phones (#604).
Improved PHPDoc descriptions and fixed PHPStan errors across the codebase.
open-in-editor on Windows – installer now registers the protocol via AutoLaunchProtocolsFromOrigins, suppressing the browser&apos;s &quot;Open external app?&quot; confirmation prompt (#573).
</description>
		<content:encoded><![CDATA[
		<p>A maintenance release focused on CSP-friendly assets, mobile-friendly error pages, and a couple of handy API additions. Expect cleaner nonce handling, better behavior on phones, and a bar.js that no longer trips strict Content Security Policies.</p>
<ul>
<li><strong>script-src-elem support in Helpers::getNonce()</strong> – nonces are now also picked up from the <code>script-src-elem</code> CSP directive, not just <code>script-src</code> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3958438647" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/612" data-hovercard-type="pull_request" data-hovercard-url="/nette/tracy/pull/612/hovercard" href="https://github.com/nette/tracy/pull/612">#612</a>).</li>
<li><strong>CSP-friendly Tracy Bar</strong> – replaced the inline <code>onload</code> attribute in bar.js with a native <code>addEventListener</code>, eliminating a common CSP violation (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4164090884" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/614" data-hovercard-type="issue" data-hovercard-url="/nette/tracy/issues/614/hovercard" href="https://github.com/nette/tracy/issues/614">#614</a>).</li>
<li><strong>FileSession::clean()</strong> – emits a warning when the session directory is not readable, making misconfigured storage easier to diagnose (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1179574698" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/538" data-hovercard-type="issue" data-hovercard-url="/nette/tracy/issues/538/hovercard" href="https://github.com/nette/tracy/issues/538">#538</a>).</li>
<li><strong>Mobile-friendly error pages</strong> – BlueScreen and the 500 error template now include a proper viewport meta tag, so exceptions no longer render microscopically on phones (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3500373316" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/604" data-hovercard-type="pull_request" data-hovercard-url="/nette/tracy/pull/604/hovercard" href="https://github.com/nette/tracy/pull/604">#604</a>).</li>
<li>Improved PHPDoc descriptions and fixed PHPStan errors across the codebase.</li>
<li><strong>open-in-editor on Windows</strong> – installer now registers the protocol via <code>AutoLaunchProtocolsFromOrigins</code>, suppressing the browser's "Open external app?" confirmation prompt (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1936474315" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/573" data-hovercard-type="pull_request" data-hovercard-url="/nette/tracy/pull/573/hovercard" href="https://github.com/nette/tracy/pull/573">#573</a>).</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 22 Apr 2026 06:05:29 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.11.4</guid>
	</item>
	<item>
		<title>Database v3.2.9</title>
		<link>https://github.com/nette/database/releases/tag/v3.2.9</link>
		<description>This release brings a set of focused exception types that let you catch specific database failure modes (deadlocks, lock timeouts, check constraint violations, lost connections) instead of wrestling with generic driver errors. ActiveRow and Selection now expose getExplorer() for direct access to the underlying Explorer, and the reflection layer has been refactored for more consistent metadata across drivers.
✨ New Features

getExplorer() – ActiveRow and Selection now expose the underlying Explorer instance, no more jumping through hoops to get back to it
DeadlockException – catch deadlocks and serialization failures distinctly from other driver errors, so retry logic can stay surgical
LockTimeoutException – a dedicated exception for lock wait timeouts
CheckConstraintViolationException – check constraint violations now get their own class instead of being lumped with generic constraint errors
ConnectionLostException – distinguish dropped connections from other driver failures, making reconnect strategies much cleaner
Docker Compose setup – a ready-to-run Compose configuration for spinning up test databases locally

♻️ Code Refactoring

Drivers reflection output – unified FK row shape across drivers, simplified MsSql getIndexes SQL, parameterized SQLite PRAGMA queries, and ForeignKey::$name is now a non-nullable string

📦 Maintenance

Improved PHPDoc descriptions, phpDoc types, and native type declarations across the codebase
</description>
		<content:encoded><![CDATA[
		<p>This release brings a set of focused exception types that let you catch specific database failure modes (deadlocks, lock timeouts, check constraint violations, lost connections) instead of wrestling with generic driver errors. ActiveRow and Selection now expose <code>getExplorer()</code> for direct access to the underlying Explorer, and the reflection layer has been refactored for more consistent metadata across drivers.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>getExplorer()</strong> – <code>ActiveRow</code> and <code>Selection</code> now expose the underlying <code>Explorer</code> instance, no more jumping through hoops to get back to it</li>
<li><strong>DeadlockException</strong> – catch deadlocks and serialization failures distinctly from other driver errors, so retry logic can stay surgical</li>
<li><strong>LockTimeoutException</strong> – a dedicated exception for lock wait timeouts</li>
<li><strong>CheckConstraintViolationException</strong> – check constraint violations now get their own class instead of being lumped with generic constraint errors</li>
<li><strong>ConnectionLostException</strong> – distinguish dropped connections from other driver failures, making reconnect strategies much cleaner</li>
<li><strong>Docker Compose setup</strong> – a ready-to-run Compose configuration for spinning up test databases locally</li>
</ul>
<h2>♻️ Code Refactoring</h2>
<ul>
<li><strong>Drivers reflection output</strong> – unified FK row shape across drivers, simplified MsSql <code>getIndexes</code> SQL, parameterized SQLite PRAGMA queries, and <code>ForeignKey::$name</code> is now a non-nullable string</li>
</ul>
<h2>📦 Maintenance</h2>
<ul>
<li>Improved PHPDoc descriptions, phpDoc types, and native type declarations across the codebase</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 22 Apr 2026 05:29:34 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/database/releases/tag/v3.2.9</guid>
	</item>
	<item>
		<title>Mail v4.1.0</title>
		<link>https://github.com/nette/mail/releases/tag/v4.1.0</link>
		<description>This release introduces CssInliner – a brand-new component that brings CSS-to-inline-style conversion directly into Nette Mail. The minimum PHP version has been raised to 8.2, and static analysis is now a mandatory part of the build pipeline.


Minimum PHP version raised from 8.0 to 8.2 – time to upgrade if you haven&apos;t already


Improved PHPDoc types and descriptions for better IDE support and static analysis accuracy


CssInliner – converts &lt;style&gt; rules into inline style attributes, making your HTML emails render consistently across email clients. Features a single-regex tokenizer, full CSS nesting support, Dom\HTMLDocument selector matching (PHP 8.4+), and automatic Outlook-compatible HTML attribute generation (bgcolor, width, align, etc.). &lt;style&gt; tags are preserved so @media queries keep working.

</description>
		<content:encoded><![CDATA[
		<p>This release introduces <strong>CssInliner</strong> – a brand-new component that brings CSS-to-inline-style conversion directly into Nette Mail. The minimum PHP version has been raised to 8.2, and static analysis is now a mandatory part of the build pipeline.</p>
<ul>
<li>
<p>Minimum PHP version raised from 8.0 to <strong>8.2</strong> – time to upgrade if you haven't already</p>
</li>
<li>
<p>Improved PHPDoc types and descriptions for better IDE support and static analysis accuracy</p>
</li>
<li>
<p><strong>CssInliner</strong> – converts <code>&lt;style&gt;</code> rules into inline <code>style</code> attributes, making your HTML emails render consistently across email clients. Features a single-regex tokenizer, full CSS nesting support, <code>Dom\HTMLDocument</code> selector matching (PHP 8.4+), and automatic Outlook-compatible HTML attribute generation (<code>bgcolor</code>, <code>width</code>, <code>align</code>, etc.). <code>&lt;style&gt;</code> tags are preserved so <code>@media</code> queries keep working.</p>
</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 27 Mar 2026 01:21:29 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/mail/releases/tag/v4.1.0</guid>
	</item>
	<item>
		<title>Latte v3.1.3</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.3</link>
		<description>Latte 3.1.3 brings two powerful new engine features – automatic dedentation and scoped loop variables – alongside a fresh batch of filters that make everyday template work smoother.
✨ New Features

Feature::Dedent – removes structural indentation from paired tag content, so your generated HTML stays clean regardless of how deeply you nest your Latte tags
Feature::ScopedLoopVariables – variables introduced by {foreach} now live only inside the loop body, preventing accidental leaks into the surrounding scope (supports destructuring via ListNode too)
|commas filter – joins array elements with ,  and supports a custom last-item glue (e.g. {$items|commas:&apos; and &apos;} → a, b and c)
|column filter – extracts values from a single column of a multidimensional array or iterable, mirroring PHP&apos;s array_column()
|limit filter – a friendlier wrapper around |slice with swapped arguments: limit first, offset second, and keys preserved by default
|slice – now works with iterators, not just arrays and strings
|padLeft, |padRight – now accept int|float values in addition to strings (#408)

♻️ Code Refactoring

Helpers::sortBeforeAfter() – reimplemented using Kahn&apos;s algorithm for topological sorting, making extension ordering both faster and more correct
Engine::addDefaultExtensions() – extracted into its own method for better extensibility
</description>
		<content:encoded><![CDATA[
		<p>Latte 3.1.3 brings two powerful new engine features – automatic dedentation and scoped loop variables – alongside a fresh batch of filters that make everyday template work smoother.</p>
<h2>✨ New Features</h2>
<ul>
<li><strong>Feature::Dedent</strong> – removes structural indentation from paired tag content, so your generated HTML stays clean regardless of how deeply you nest your Latte tags</li>
<li><strong>Feature::ScopedLoopVariables</strong> – variables introduced by <code>{foreach}</code> now live only inside the loop body, preventing accidental leaks into the surrounding scope (supports destructuring via <code>ListNode</code> too)</li>
<li><strong>|commas</strong> filter – joins array elements with <code>, </code> and supports a custom last-item glue (e.g. <code>{$items|commas:' and '}</code> → <code>a, b and c</code>)</li>
<li><strong>|column</strong> filter – extracts values from a single column of a multidimensional array or iterable, mirroring PHP's <code>array_column()</code></li>
<li><strong>|limit</strong> filter – a friendlier wrapper around <code>|slice</code> with swapped arguments: limit first, offset second, and keys preserved by default</li>
<li><strong>|slice</strong> – now works with iterators, not just arrays and strings</li>
<li><strong>|padLeft, |padRight</strong> – now accept <code>int|float</code> values in addition to strings (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3995709642" data-permission-text="Title is private" data-url="https://github.com/nette/latte/issues/408" data-hovercard-type="issue" data-hovercard-url="/nette/latte/issues/408/hovercard" href="https://github.com/nette/latte/issues/408">#408</a>)</li>
</ul>
<h2>♻️ Code Refactoring</h2>
<ul>
<li><strong>Helpers::sortBeforeAfter()</strong> – reimplemented using Kahn's algorithm for topological sorting, making extension ordering both faster and more correct</li>
<li><strong>Engine::addDefaultExtensions()</strong> – extracted into its own method for better extensibility</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 22 Mar 2026 23:05:54 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.3</guid>
	</item>
	<item>
		<title>Caching v3.4.1</title>
		<link>https://github.com/nette/caching/releases/tag/v3.4.1</link>
		<description>This release is all about code quality and tooling. PHPStan static analysis is now a mandatory part of the CI pipeline with nette/phpstan-rules, phpDoc types have been tightened across the board, and the codebase follows stricter coding standards.</description>
		<content:encoded><![CDATA[
		<p>This release is all about code quality and tooling. PHPStan static analysis is now a mandatory part of the CI pipeline with <code>nette/phpstan-rules</code>, phpDoc types have been tightened across the board, and the codebase follows stricter coding standards.</p>
		]]></content:encoded>
		<pubDate>Wed, 25 Feb 2026 23:07:19 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/caching/releases/tag/v3.4.1</guid>
	</item>
	<item>
		<title>Latte v3.1.2</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.2</link>
		<description>Latte 3.1.2 introduces a clean feature flag system, tightens up the compiler API with two breaking changes, and brings the codebase under stricter static analysis. If you&apos;re extending the compiler, pay attention to the TokenStream and custom function changes below.

Feature enum with setFeature()/hasFeature() – a unified way to toggle engine capabilities like StrictTypes, StrictParsing, and MigrationWarnings. The old methods (setStrictTypes(), setStrictParsing(), setMigrationWarnings()) still work but are now deprecated in favor of the enum-based API.
setCacheDirectory() replaces the old setTempDirectory() – because &quot;temp&quot; was way too easily confused with &quot;template&quot;. The old method still works but is deprecated.
LinterExtension now correctly validates ::class expressions – previously {=UnknownClass::class} slipped through validation because it was handled as a class constant instead of a class type check.
Added missing native type declarations across the codebase.
Improved phpDoc types and descriptions.
Unified declare(strict_types=1) to single-line format.
</description>
		<content:encoded><![CDATA[
		<p>Latte 3.1.2 introduces a clean feature flag system, tightens up the compiler API with two breaking changes, and brings the codebase under stricter static analysis. If you're extending the compiler, pay attention to the TokenStream and custom function changes below.</p>
<ul>
<li><strong>Feature</strong> enum with <strong>setFeature()</strong>/<strong>hasFeature()</strong> – a unified way to toggle engine capabilities like <code>StrictTypes</code>, <code>StrictParsing</code>, and <code>MigrationWarnings</code>. The old methods (<code>setStrictTypes()</code>, <code>setStrictParsing()</code>, <code>setMigrationWarnings()</code>) still work but are now deprecated in favor of the enum-based API.</li>
<li><strong>setCacheDirectory()</strong> replaces the old <code>setTempDirectory()</code> – because "temp" was way too easily confused with "template". The old method still works but is deprecated.</li>
<li><strong>LinterExtension</strong> now correctly validates <code>::class</code> expressions – previously <code>{=UnknownClass::class}</code> slipped through validation because it was handled as a class constant instead of a class type check.</li>
<li>Added missing native type declarations across the codebase.</li>
<li>Improved phpDoc types and descriptions.</li>
<li>Unified <code>declare(strict_types=1)</code> to single-line format.</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 25 Feb 2026 01:37:42 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.2</guid>
	</item>
	<item>
		<title>Latte v3.0.26</title>
		<link>https://github.com/nette/latte/releases/tag/v3.0.26</link>
		<description>
Feature class with setFeature()/hasFeature() – a unified way to toggle engine capabilities. Existing methods like setStrictTypes() and setStrictParsing() now delegate to this system, so you can use either style. New features can be added without cluttering the Engine API.
setCacheDirectory() replaces the old setTempDirectory() – because &quot;temp&quot; was too easily confused with &quot;template&quot;. The old method still works but consider it deprecated.
Fixed ! operator priority – the logical NOT operator was incorrectly placed at the same precedence level as bitwise NOT and type casts, above instanceof. It now correctly sits below instanceof, matching PHP&apos;s actual operator precedence.
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>Feature</strong> class with <strong>setFeature()</strong>/<strong>hasFeature()</strong> – a unified way to toggle engine capabilities. Existing methods like <code>setStrictTypes()</code> and <code>setStrictParsing()</code> now delegate to this system, so you can use either style. New features can be added without cluttering the Engine API.</li>
<li><strong>setCacheDirectory()</strong> replaces the old <code>setTempDirectory()</code> – because "temp" was too easily confused with "template". The old method still works but consider it deprecated.</li>
<li>Fixed <strong><code>!</code> operator priority</strong> – the logical NOT operator was incorrectly placed at the same precedence level as bitwise NOT and type casts, above <code>instanceof</code>. It now correctly sits below <code>instanceof</code>, matching PHP's actual operator precedence.</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 25 Feb 2026 00:02:23 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.0.26</guid>
	</item>
	<item>
		<title>Robot Loader v4.1.2</title>
		<link>https://github.com/nette/robot-loader/releases/tag/v4.1.2</link>
		<description>A code quality release that tightens static analysis and cleans up internals.

Fixed all PHPStan errors and improved phpDoc annotations
Switched to singleline declare statements across the codebase
</description>
		<content:encoded><![CDATA[
		<p>A code quality release that tightens static analysis and cleans up internals.</p>
<ul>
<li>Fixed all PHPStan errors and improved phpDoc annotations</li>
<li>Switched to singleline <code>declare</code> statements across the codebase</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 23 Feb 2026 04:21:58 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/robot-loader/releases/tag/v4.1.2</guid>
	</item>
	<item>
		<title>Routing v3.1.3</title>
		<link>https://github.com/nette/routing/releases/tag/v3.1.3</link>
		<description>A code quality release that tightens static analysis and cleans up internals.

Fixed all PHPStan errors and improved phpDoc annotations
Switched to singleline declare statements across the codebase
</description>
		<content:encoded><![CDATA[
		<p>A code quality release that tightens static analysis and cleans up internals.</p>
<ul>
<li>Fixed all PHPStan errors and improved phpDoc annotations</li>
<li>Switched to singleline <code>declare</code> statements across the codebase</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 23 Feb 2026 04:08:41 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/routing/releases/tag/v3.1.3</guid>
	</item>
	<item>
		<title>Schema v1.3.5</title>
		<link>https://github.com/nette/schema/releases/tag/v1.3.5</link>
		<description>A code quality release that tightens static analysis and cleans up internals.

Fixed all PHPStan errors and improved phpDoc annotations
Switched to singleline declare statements across the codebase
</description>
		<content:encoded><![CDATA[
		<p>A code quality release that tightens static analysis and cleans up internals.</p>
<ul>
<li>Fixed all PHPStan errors and improved phpDoc annotations</li>
<li>Switched to singleline <code>declare</code> statements across the codebase</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 23 Feb 2026 03:41:05 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/schema/releases/tag/v1.3.5</guid>
	</item>
	<item>
		<title>Safe Stream v3.0.4</title>
		<link>https://github.com/nette/safe-stream/releases/tag/v3.0.4</link>
		<description>A code quality release that tightens static analysis and cleans up internals.

Fixed all PHPStan errors and improved phpDoc annotations
Switched to singleline declare statements across the codebase
</description>
		<content:encoded><![CDATA[
		<p>A code quality release that tightens static analysis and cleans up internals.</p>
<ul>
<li>Fixed all PHPStan errors and improved phpDoc annotations</li>
<li>Switched to singleline <code>declare</code> statements across the codebase</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 23 Feb 2026 03:34:56 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/safe-stream/releases/tag/v3.0.4</guid>
	</item>
	<item>
		<title>Tracy v2.11.2</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.11.2</link>
		<description>♻️ Code Refactoring

Templates converted to Latte-like syntax, paving the way for a cleaner templating pipeline
Environment guards relocated from Debugger to the individual strategy classes, improving separation of concerns

🔧 Build &amp; CI

Upgraded to PHPStan level 8 — the strictest static analysis level is now passing
</description>
		<content:encoded><![CDATA[
		<h2>♻️ Code Refactoring</h2>
<ul>
<li><strong>Templates converted</strong> to Latte-like syntax, paving the way for a cleaner templating pipeline</li>
<li><strong>Environment guards</strong> relocated from <code>Debugger</code> to the individual strategy classes, improving separation of concerns</li>
</ul>
<h2>🔧 Build &amp; CI</h2>
<ul>
<li>Upgraded to <strong>PHPStan level 8</strong> — the strictest static analysis level is now passing</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 20 Feb 2026 06:33:42 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.11.2</guid>
	</item>
	<item>
		<title>Tracy v2.11.3</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.11.3</link>
		<description>
Templates converted to Latte-like syntax, paving the way for a cleaner templating pipeline
Environment guards relocated from Debugger to the individual strategy classes, improving separation of concerns
Upgraded to PHPStan level 8 — the strictest static analysis level is now passing
</description>
		<content:encoded><![CDATA[
		<ul>
<li><strong>Templates converted</strong> to Latte-like syntax, paving the way for a cleaner templating pipeline</li>
<li><strong>Environment guards</strong> relocated from <code>Debugger</code> to the individual strategy classes, improving separation of concerns</li>
<li>Upgraded to <strong>PHPStan level 8</strong> — the strictest static analysis level is now passing</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 20 Feb 2026 06:33:42 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.11.3</guid>
	</item>
	<item>
		<title>Utils v4.1.3</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.3</link>
		<description>A maintenance release focused on code quality: stricter types, better PHPDoc annotations, and PHPStan now runs as a mandatory CI check. No breaking changes.</description>
		<content:encoded><![CDATA[
		<p>A maintenance release focused on code quality: stricter types, better PHPDoc annotations, and PHPStan now runs as a mandatory CI check. No breaking changes.</p>
		]]></content:encoded>
		<pubDate>Fri, 13 Feb 2026 03:08:55 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.3</guid>
	</item>
	<item>
		<title>Php Generator v4.2.1</title>
		<link>https://github.com/nette/php-generator/releases/tag/v4.2.1</link>
		<description>This release focuses on making namespaces and classes work together more naturally. Classes now know which namespace they belong to, constructors accept fully qualified names, and a new unified add() method on PhpFile ties it all together. Under the hood, the Factory got a thorough refactoring and the codebase passed its first mandatory static analysis check.


PhpNamespace::add() now automatically assigns itself as the namespace of any ClassLike passed to it. If your code relied on getNamespace() returning null after adding a class to a namespace, you&apos;ll need to update that assumption.


PhpFile::add() – a single entry point for adding classes, interfaces, traits, enums, functions, and namespaces to a file. It handles namespace creation and bracket syntax automatically, so you can build a complete file with just add() calls.


ClassLike::getFullName() – returns the fully qualified name when the class belongs to a namespace (e.g., App\Model\User), the short name otherwise, or null for anonymous classes.


ClassLike constructors now accept FQN – pass &apos;App\Model\User&apos; and the namespace is extracted automatically. No need to create the namespace separately for simple cases.


PhpNamespace::add() accepts GlobalFunction – the unified add() method now handles functions alongside class-like types, making the namespace API more consistent.


The $namespace parameter in ClassLike constructors is deprecated. Use setNamespace() instead. The old signature still works for now, but will be removed in a future version.

</description>
		<content:encoded><![CDATA[
		<p>This release focuses on making namespaces and classes work together more naturally. Classes now know which namespace they belong to, constructors accept fully qualified names, and a new unified <code>add()</code> method on PhpFile ties it all together. Under the hood, the Factory got a thorough refactoring and the codebase passed its first mandatory static analysis check.</p>
<ul>
<li>
<p><strong>PhpNamespace::add()</strong> now automatically assigns itself as the namespace of any ClassLike passed to it. If your code relied on <code>getNamespace()</code> returning <code>null</code> after adding a class to a namespace, you'll need to update that assumption.</p>
</li>
<li>
<p><strong>PhpFile::add()</strong> – a single entry point for adding classes, interfaces, traits, enums, functions, and namespaces to a file. It handles namespace creation and bracket syntax automatically, so you can build a complete file with just <code>add()</code> calls.</p>
</li>
<li>
<p><strong>ClassLike::getFullName()</strong> – returns the fully qualified name when the class belongs to a namespace (e.g., <code>App\Model\User</code>), the short name otherwise, or <code>null</code> for anonymous classes.</p>
</li>
<li>
<p><strong>ClassLike constructors now accept FQN</strong> – pass <code>'App\Model\User'</code> and the namespace is extracted automatically. No need to create the namespace separately for simple cases.</p>
</li>
<li>
<p><strong>PhpNamespace::add() accepts GlobalFunction</strong> – the unified <code>add()</code> method now handles functions alongside class-like types, making the namespace API more consistent.</p>
</li>
<li>
<p>The <strong><code>$namespace</code> parameter in ClassLike constructors</strong> is deprecated. Use <code>setNamespace()</code> instead. The old signature still works for now, but will be removed in a future version.</p>
</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 09 Feb 2026 05:49:00 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/php-generator/releases/tag/v4.2.1</guid>
	</item>
	<item>
		<title>Php Generator v4.2.2</title>
		<link>https://github.com/nette/php-generator/releases/tag/v4.2.2</link>
		<description>This release focuses on making namespaces and classes work together more naturally. Classes now know which namespace they belong to, constructors accept fully qualified names, and a new unified add() method on PhpFile ties it all together. Under the hood, the Factory got a thorough refactoring and the codebase passed its first mandatory static analysis check.


PhpNamespace::add() now automatically assigns itself as the namespace of any ClassLike passed to it. If your code relied on getNamespace() returning null after adding a class to a namespace, you&apos;ll need to update that assumption.


PhpFile::add() – a single entry point for adding classes, interfaces, traits, enums, functions, and namespaces to a file. It handles namespace creation and bracket syntax automatically, so you can build a complete file with just add() calls.


ClassLike::getFullName() – returns the fully qualified name when the class belongs to a namespace (e.g., App\Model\User), the short name otherwise, or null for anonymous classes.


ClassLike constructors now accept FQN – pass &apos;App\Model\User&apos; and the namespace is extracted automatically. No need to create the namespace separately for simple cases.


PhpNamespace::add() accepts GlobalFunction – the unified add() method now handles functions alongside class-like types, making the namespace API more consistent.


The $namespace parameter in ClassLike constructors is deprecated. Use setNamespace() instead. The old signature still works for now, but will be removed in a future version.

</description>
		<content:encoded><![CDATA[
		<p>This release focuses on making namespaces and classes work together more naturally. Classes now know which namespace they belong to, constructors accept fully qualified names, and a new unified <code>add()</code> method on PhpFile ties it all together. Under the hood, the Factory got a thorough refactoring and the codebase passed its first mandatory static analysis check.</p>
<ul>
<li>
<p><strong>PhpNamespace::add()</strong> now automatically assigns itself as the namespace of any ClassLike passed to it. If your code relied on <code>getNamespace()</code> returning <code>null</code> after adding a class to a namespace, you'll need to update that assumption.</p>
</li>
<li>
<p><strong>PhpFile::add()</strong> – a single entry point for adding classes, interfaces, traits, enums, functions, and namespaces to a file. It handles namespace creation and bracket syntax automatically, so you can build a complete file with just <code>add()</code> calls.</p>
</li>
<li>
<p><strong>ClassLike::getFullName()</strong> – returns the fully qualified name when the class belongs to a namespace (e.g., <code>App\Model\User</code>), the short name otherwise, or <code>null</code> for anonymous classes.</p>
</li>
<li>
<p><strong>ClassLike constructors now accept FQN</strong> – pass <code>'App\Model\User'</code> and the namespace is extracted automatically. No need to create the namespace separately for simple cases.</p>
</li>
<li>
<p><strong>PhpNamespace::add() accepts GlobalFunction</strong> – the unified <code>add()</code> method now handles functions alongside class-like types, making the namespace API more consistent.</p>
</li>
<li>
<p>The <strong><code>$namespace</code> parameter in ClassLike constructors</strong> is deprecated. Use <code>setNamespace()</code> instead. The old signature still works for now, but will be removed in a future version.</p>
</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 09 Feb 2026 05:49:00 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/php-generator/releases/tag/v4.2.2</guid>
	</item>
	<item>
		<title>Robot Loader v4.1.1</title>
		<link>https://github.com/nette/robot-loader/releases/tag/v4.1.1</link>
		<description>improved phpDoc</description>
		<content:encoded><![CDATA[
		<p>improved phpDoc</p>
		]]></content:encoded>
		<pubDate>Sun, 08 Feb 2026 15:44:59 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/robot-loader/releases/tag/v4.1.1</guid>
	</item>
	<item>
		<title>Schema v1.3.4</title>
		<link>https://github.com/nette/schema/releases/tag/v1.3.4</link>
		<description>improved phpDoc</description>
		<content:encoded><![CDATA[
		<p>improved phpDoc</p>
		]]></content:encoded>
		<pubDate>Sun, 08 Feb 2026 02:47:44 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/schema/releases/tag/v1.3.4</guid>
	</item>
	<item>
		<title>Tracy v2.11.1</title>
		<link>https://github.com/nette/tracy/releases/tag/v2.11.1</link>
		<description>✨ New Features

Dumper – added support for uninitialized lazy objects (PHP 8.4), displaying them with a (lazy) label and showing only pre-initialized properties
Source mapper – added column support, so BlueScreen can now pinpoint the exact character position in mapped source files

🐛 Bug Fixes

keysToHide now applies to bdump()/barDump() as well – previously sensitive keys were only hidden in dump() and BlueScreen (#608)
TracyExtension sets keysToHide config for Debugger too, not just for BlueScreen (#608)
Dumper correctly loads its assets even when $showBar = false (#606)
</description>
		<content:encoded><![CDATA[
		<h2>✨ New Features</h2>
<ul>
<li><strong>Dumper</strong> – added support for uninitialized lazy objects (PHP 8.4), displaying them with a <code>(lazy)</code> label and showing only pre-initialized properties</li>
<li><strong>Source mapper</strong> – added column support, so BlueScreen can now pinpoint the exact character position in mapped source files</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong><code>keysToHide</code></strong> now applies to <code>bdump()</code>/<code>barDump()</code> as well – previously sensitive keys were only hidden in <code>dump()</code> and BlueScreen (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3748993186" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/608" data-hovercard-type="issue" data-hovercard-url="/nette/tracy/issues/608/hovercard" href="https://github.com/nette/tracy/issues/608">#608</a>)</li>
<li><strong>TracyExtension</strong> sets <code>keysToHide</code> config for Debugger too, not just for BlueScreen (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3748993186" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/608" data-hovercard-type="issue" data-hovercard-url="/nette/tracy/issues/608/hovercard" href="https://github.com/nette/tracy/issues/608">#608</a>)</li>
<li><strong>Dumper</strong> correctly loads its assets even when <code>$showBar = false</code> (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3509985417" data-permission-text="Title is private" data-url="https://github.com/nette/tracy/issues/606" data-hovercard-type="issue" data-hovercard-url="/nette/tracy/issues/606/hovercard" href="https://github.com/nette/tracy/issues/606">#606</a>)</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 08 Feb 2026 01:13:23 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tracy/releases/tag/v2.11.1</guid>
	</item>
	<item>
		<title>Utils v4.1.2</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.2</link>
		<description>A maintenance release focused on code quality: stricter types, better PHPDoc annotations, and PHPStan now runs as a mandatory CI check. No breaking changes.</description>
		<content:encoded><![CDATA[
		<p>A maintenance release focused on code quality: stricter types, better PHPDoc annotations, and PHPStan now runs as a mandatory CI check. No breaking changes.</p>
		]]></content:encoded>
		<pubDate>Tue, 03 Feb 2026 17:22:11 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.2</guid>
	</item>
	<item>
		<title>Tester v2.6.0</title>
		<link>https://github.com/nette/tester/releases/tag/v2.6.0</link>
		<description>Breaking Changes

Tester now uses system php.ini by default (#465)

Improvements

True parallel test execution on Windows with PHP 8.5 (utilizing fixed stream_select() with proc_open() pipes)
Fixed stdout data loss when process exits quickly
hides cursor

New Features

Global testException() now calls setUp() and tearDown()
Global test() now calls tearDown() even when test fails
Added global function testNoError()
</description>
		<content:encoded><![CDATA[
		<h2>Breaking Changes</h2>
<ul>
<li>Tester now uses system <code>php.ini</code> by default (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3784290198" data-permission-text="Title is private" data-url="https://github.com/nette/tester/issues/465" data-hovercard-type="issue" data-hovercard-url="/nette/tester/issues/465/hovercard" href="https://github.com/nette/tester/issues/465">#465</a>)</li>
</ul>
<h2>Improvements</h2>
<ul>
<li>True parallel test execution on Windows with PHP 8.5 (utilizing fixed <code>stream_select()</code> with <code>proc_open()</code> pipes)</li>
<li>Fixed stdout data loss when process exits quickly</li>
<li>hides cursor</li>
</ul>
<h2>New Features</h2>
<ul>
<li>Global <code>testException()</code> now calls <code>setUp()</code> and <code>tearDown()</code></li>
<li>Global <code>test()</code> now calls <code>tearDown()</code> even when test fails</li>
<li>Added global function <code>testNoError()</code></li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 22 Jan 2026 06:49:06 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/tester/releases/tag/v2.6.0</guid>
	</item>
	<item>
		<title>Neon v3.4.7</title>
		<link>https://github.com/nette/neon/releases/tag/v3.4.7</link>
		<description>
Encoder: invalid UTF-8 sequences are replaced with U+FFFD  #76
improved neon-lint
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Encoder: invalid UTF-8 sequences are replaced with U+FFFD  <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2872967568" data-permission-text="Title is private" data-url="https://github.com/nette/neon/issues/76" data-hovercard-type="issue" data-hovercard-url="/nette/neon/issues/76/hovercard" href="https://github.com/nette/neon/issues/76">#76</a></li>
<li>improved neon-lint</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 04 Jan 2026 08:43:41 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/neon/releases/tag/v3.4.7</guid>
	</item>
	<item>
		<title>Utils v4.1.1</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.1</link>
		<description>
Html::addText() accepts int|null for back compatibility [Closes #332][Closes #333]
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Html::addText() accepts int|null for back compatibility [Closes <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3695264020" data-permission-text="Title is private" data-url="https://github.com/nette/utils/issues/332" data-hovercard-type="issue" data-hovercard-url="/nette/utils/issues/332/hovercard" href="https://github.com/nette/utils/issues/332">#332</a>][Closes <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3698284841" data-permission-text="Title is private" data-url="https://github.com/nette/utils/issues/333" data-hovercard-type="pull_request" data-hovercard-url="/nette/utils/pull/333/hovercard" href="https://github.com/nette/utils/pull/333">#333</a>]</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 22 Dec 2025 12:08:17 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.1</guid>
	</item>
	<item>
		<title>Application v3.2.9</title>
		<link>https://github.com/nette/application/releases/tag/v3.2.9</link>
		<description>
added #[TemplateVariable]
LinkGenerator: throws an error when the link points to #[Requires(forward: true)]
</description>
		<content:encoded><![CDATA[
		<ul>
<li>added #[TemplateVariable]</li>
<li>LinkGenerator: throws an error when the link points to #[Requires(forward: true)]</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 19 Dec 2025 11:40:30 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/v3.2.9</guid>
	</item>
	<item>
		<title>Latte v3.1.1</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.1</link>
		<description>
added LinterExtension for validating filters, functions, classes and methods
linter: improved finding files, excludes temp, vendor, node_modules
support every argument syntax for clone() in PHP 8.5
added CustomFunctionCallNode for custom functions
refactor: decentralize operator precedence to individual nodes
*CallableNode replaced with solution with VariadicPlaceholder (BC break)
ErrorSuppressNode &amp; NotNode merged into UnaryOpNode (BC break)
deprecated PrintContext::infixOp(), prefixOp(), postfixOp() (BC break)
fixed operator ! priority
</description>
		<content:encoded><![CDATA[
		<ul>
<li>added LinterExtension for validating filters, functions, classes and methods</li>
<li>linter: improved finding files, excludes temp, vendor, node_modules</li>
<li>support every argument syntax for <code>clone()</code> in PHP 8.5</li>
<li>added CustomFunctionCallNode for custom functions</li>
<li>refactor: decentralize operator precedence to individual nodes</li>
<li>*CallableNode replaced with solution with VariadicPlaceholder (BC break)</li>
<li>ErrorSuppressNode &amp; NotNode merged into UnaryOpNode (BC break)</li>
<li>deprecated <code>PrintContext::infixOp()</code>, <code>prefixOp()</code>, <code>postfixOp()</code> (BC break)</li>
<li>fixed operator ! priority</li>
</ul>
		]]></content:encoded>
		<pubDate>Thu, 18 Dec 2025 22:42:28 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.1</guid>
	</item>
	<item>
		<title>Utils v4.1.0</title>
		<link>https://github.com/nette/utils/releases/tag/v4.1.0</link>
		<description>
requires PHP 8.2
DateTime: strict behavior (BC break)
Strings::webalize() requires INTL extension
StaticClass: is not overriding __callStatic()
</description>
		<content:encoded><![CDATA[
		<ul>
<li>requires PHP 8.2</li>
<li>DateTime: strict behavior (BC break)</li>
<li>Strings::webalize() requires INTL extension</li>
<li>StaticClass: is not overriding __callStatic()</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 01 Dec 2025 17:45:58 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.1.0</guid>
	</item>
	<item>
		<title>Utils v4.0.10</title>
		<link>https://github.com/nette/utils/releases/tag/v4.0.10</link>
		<description>
added Type::with()
added Type::fromValue()
added Helpers::splitClassName()
added Iterables::repeatable()
Finder: is_file() does not work with symlinks under Windows
</description>
		<content:encoded><![CDATA[
		<ul>
<li>added <code>Type::with()</code></li>
<li>added <code>Type::fromValue()</code></li>
<li>added <code>Helpers::splitClassName()</code></li>
<li>added <code>Iterables::repeatable()</code></li>
<li>Finder: <code>is_file()</code> does not work with symlinks under Windows</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 01 Dec 2025 17:45:08 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/utils/releases/tag/v4.0.10</guid>
	</item>
	<item>
		<title>Latte v3.0.25</title>
		<link>https://github.com/nette/latte/releases/tag/v3.0.25</link>
		<description>
Escaper: supports converting HTML =&gt; TEXT
Escaper: fixed converting between HTML/ATTR &lt;=&gt; HTML
added ModifierNode::removeFilter()
linter: added assets extension
</description>
		<content:encoded><![CDATA[
		<ul>
<li>Escaper: supports converting HTML =&gt; TEXT</li>
<li>Escaper: fixed converting between HTML/ATTR <code>&lt;=&gt;</code> HTML</li>
<li>added <code>ModifierNode::removeFilter()</code></li>
<li>linter: added assets extension</li>
</ul>
		]]></content:encoded>
		<pubDate>Fri, 28 Nov 2025 17:39:12 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.0.25</guid>
	</item>
	<item>
		<title>Latte v3.1.0</title>
		<link>https://github.com/nette/latte/releases/tag/v3.1.0</link>
		<description>This major release introduces Smart HTML Attributes, strict_types by default, and several syntax improvements. It requires PHP 8.2+.
Smart HTML Attributes

Null values: Attributes with null values are now dropped instead of rendering as empty strings.
Boolean attributes: Attributes like checked or disabled render conditionally based on truthy/falsey values.
Array support: class and style attributes now accept arrays (e.g., class=&quot;{[active: $cond]}&quot;).
Data attributes: data-* attributes automatically JSON-serialize non-string values (arrays, objects, booleans).
Aria attributes: aria-* attributes render boolean values as &quot;true&quot;/&quot;false&quot;.
Type checking: Passing invalid types (arrays, objects) to standard attributes now triggers a warning and omits the attribute.

New Features

Added n:elseif support.
Added nullsafe filter operator ?| (e.g., {$var?|upper}).
Added |toggle filter for manual boolean attribute control.
Support for unquoted n-attribute syntax: n:if={$cond}.
Added Engine::setMigrationWarnings() to help detect changes in attribute rendering.

Breaking Changes &amp; Deprecations

strictTypes is now enabled by default.
Using $this and $__* variables in templates is deprecated.
The undefined unsafe operator ??-&gt; is deprecated (use ?-&gt;).
Global constants should now be prefixed with a slash (e.g., \PHP_VERSION).
Engine::addFilterLoader() is deprecated.
</description>
		<content:encoded><![CDATA[
		<p>This major release introduces Smart HTML Attributes, <code>strict_types</code> by default, and several syntax improvements. It requires PHP 8.2+.</p>
<p><strong>Smart HTML Attributes</strong></p>
<ul>
<li><strong>Null values:</strong> Attributes with <code>null</code> values are now dropped instead of rendering as empty strings.</li>
<li><strong>Boolean attributes:</strong> Attributes like <code>checked</code> or <code>disabled</code> render conditionally based on truthy/falsey values.</li>
<li><strong>Array support:</strong> <code>class</code> and <code>style</code> attributes now accept arrays (e.g., <code>class="{[active: $cond]}"</code>).</li>
<li><strong>Data attributes:</strong> <code>data-*</code> attributes automatically JSON-serialize non-string values (arrays, objects, booleans).</li>
<li><strong>Aria attributes:</strong> <code>aria-*</code> attributes render boolean values as <code>"true"</code>/<code>"false"</code>.</li>
<li><strong>Type checking:</strong> Passing invalid types (arrays, objects) to standard attributes now triggers a warning and omits the attribute.</li>
</ul>
<p><strong>New Features</strong></p>
<ul>
<li>Added <code>n:elseif</code> support.</li>
<li>Added nullsafe filter operator <code>?|</code> (e.g., <code>{$var?|upper}</code>).</li>
<li>Added <code>|toggle</code> filter for manual boolean attribute control.</li>
<li>Support for unquoted n-attribute syntax: <code>n:if={$cond}</code>.</li>
<li>Added <code>Engine::setMigrationWarnings()</code> to help detect changes in attribute rendering.</li>
</ul>
<p><strong>Breaking Changes &amp; Deprecations</strong></p>
<ul>
<li><code>strictTypes</code> is now enabled by default.</li>
<li>Using <code>$this</code> and <code>$__*</code> variables in templates is deprecated.</li>
<li>The undefined unsafe operator <code>??-&gt;</code> is deprecated (use <code>?-&gt;</code>).</li>
<li>Global constants should now be prefixed with a slash (e.g., <code>\PHP_VERSION</code>).</li>
<li><code>Engine::addFilterLoader()</code> is deprecated.</li>
</ul>
		]]></content:encoded>
		<pubDate>Wed, 26 Nov 2025 18:46:40 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/latte/releases/tag/v3.1.0</guid>
	</item>
	<item>
		<title>Neon v3.4.6</title>
		<link>https://github.com/nette/neon/releases/tag/v3.4.6</link>
		<description>
fixed mixed indents in block strings (#78)
Nodes: removes null nodes after traversal
adjusted exception message
</description>
		<content:encoded><![CDATA[
		<ul>
<li>fixed mixed indents in block strings (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3159453298" data-permission-text="Title is private" data-url="https://github.com/nette/neon/issues/78" data-hovercard-type="pull_request" data-hovercard-url="/nette/neon/pull/78/hovercard" href="https://github.com/nette/neon/pull/78">#78</a>)</li>
<li>Nodes: removes null nodes after traversal</li>
<li>adjusted exception message</li>
</ul>
		]]></content:encoded>
		<pubDate>Tue, 25 Nov 2025 13:13:55 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/neon/releases/tag/v3.4.6</guid>
	</item>
	<item>
		<title>Application v3.2.8</title>
		<link>https://github.com/nette/application/releases/tag/v3.2.8</link>
		<description>
support for PHP 8.5
compatible with Latte 3.1
LinkGenerator: do not pass defaults of #[Parameter] (#355)
PresenterFactoryCallback: fixed $invalidLinkMode can&apos;t be overwritten by config [Closes#337]
</description>
		<content:encoded><![CDATA[
		<ul>
<li>support for PHP 8.5</li>
<li>compatible with Latte 3.1</li>
<li>LinkGenerator: do not pass defaults of #[Parameter] (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="3338712988" data-permission-text="Title is private" data-url="https://github.com/nette/application/issues/355" data-hovercard-type="pull_request" data-hovercard-url="/nette/application/pull/355/hovercard" href="https://github.com/nette/application/pull/355">#355</a>)</li>
<li>PresenterFactoryCallback: fixed $invalidLinkMode can't be overwritten by config [Closes#337]</li>
</ul>
		]]></content:encoded>
		<pubDate>Mon, 24 Nov 2025 00:00:50 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/application/releases/tag/v3.2.8</guid>
	</item>
	<item>
		<title>Forms v3.2.8</title>
		<link>https://github.com/nette/forms/releases/tag/v3.2.8</link>
		<description>
support for PHP 8.5
compatible with Latte 3.1
CheckboxList, RadioList::getControl() return empty element when has no items
</description>
		<content:encoded><![CDATA[
		<ul>
<li>support for PHP 8.5</li>
<li>compatible with Latte 3.1</li>
<li>CheckboxList, <code>RadioList::getControl()</code> return empty element when has no items</li>
</ul>
		]]></content:encoded>
		<pubDate>Sun, 23 Nov 2025 20:37:49 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/forms/releases/tag/v3.2.8</guid>
	</item>
	<item>
		<title>Component Model v3.1.3</title>
		<link>https://github.com/nette/component-model/releases/tag/v3.1.3</link>
		<description>support for PHP 8.5</description>
		<content:encoded><![CDATA[
		<p>support for PHP 8.5</p>
		]]></content:encoded>
		<pubDate>Sat, 22 Nov 2025 18:58:22 +0000</pubDate>
		<guid isPermaLink="true">https://github.com/nette/component-model/releases/tag/v3.1.3</guid>
	</item>
</channel>
</rss>
