Marco Ricci commited on 2025-06-15 09:30:13
Zeige 18 geänderte Dateien mit 190 Einfügungen und 218 Löschungen.
(Oops.)
... | ... |
@@ -1,15 +0,0 @@ |
1 |
-### Changed |
|
2 |
- |
|
3 |
- - The export handlers for "storeroom" and "vault-native" configuration |
|
4 |
- data, |
|
5 |
- [`export_storeroom_data`][derivepassphrase.exporter.storeroom.export_storeroom_data] |
|
6 |
- and |
|
7 |
- [`export_vault_native_data`][derivepassphrase.exporter.vault_native.export_vault_native_data] |
|
8 |
- configuration data now both support a unified interface: |
|
9 |
- [`ExportVaultConfigDataFunction`][derivepassphrase.exporter.ExportVaultConfigDataFunction]. |
|
10 |
- A new dispatch function |
|
11 |
- [`export_vault_config_data`][derivepassphrase.exporter.export_vault_config_data] |
|
12 |
- automatically calls the correct backend, based on the requested format. |
|
13 |
- |
|
14 |
- This is a **breaking API change** due to the change in function |
|
15 |
- parameter names and return types. |
... | ... |
@@ -1,11 +0,0 @@ |
1 |
-### Changed |
|
2 |
- |
|
3 |
- - `KeyCommentPair` from [`derivepassphrase._types`][], and `KeyPair` and |
|
4 |
- `MasterKeys` from [`derivepassphrase.exporter.storeroom`][], have been |
|
5 |
- converted to [`NamedTuple`s][typing.NamedTuple] and renamed to |
|
6 |
- [`SSHKeyCommentPair`][derivepassphrase._types.SSHKeyCommentPair], |
|
7 |
- [`StoreroomKeyPair`][derivepassphrase._types.StoreroomKeyPair] and |
|
8 |
- [`StoreroomMasterKeys`][derivepassphrase._types.StoreroomMasterKeys], |
|
9 |
- respectively, in the [`derivepassphrase._types`][] module. |
|
10 |
- |
|
11 |
- This is a **breaking API change**. |
... | ... |
@@ -1,9 +0,0 @@ |
1 |
-### Fixed |
|
2 |
- |
|
3 |
- - Shell completion for `zsh` was misbehaving in the presence of colons in |
|
4 |
- the completion item. |
|
5 |
- This was due to an overzealous workaround for |
|
6 |
- [`pallets/click#2703`][CLICK_2703]. |
|
7 |
- |
|
8 |
-[CLICK_2703]: https://github.com/pallets/click/issues/2703 |
|
9 |
- |
... | ... |
@@ -1,17 +0,0 @@ |
1 |
-### Added |
|
2 |
- |
|
3 |
- - [`Vault`][derivepassphrase.vault.Vault] now can report on whether two |
|
4 |
- master passphrases are interchangable with respect to the service |
|
5 |
- passphrases they can derive. |
|
6 |
- This is an artefact of how the master passphrase is converted to the |
|
7 |
- random bit sequence with which the service passphrases are generated. |
|
8 |
- See the corresponding [FAQ entry: What are "interchangable passphrases" |
|
9 |
- in vault?][INTERCHANGABLE_PASSPHRASES] for details, including the |
|
10 |
- practical security (non-)implications. |
|
11 |
- |
|
12 |
- The `derivepassphrase vault` command-line interface does not address |
|
13 |
- this in any manner, mostly because the "non-standard" interchangable |
|
14 |
- variants of a given master password tend to be ugly to type in, and |
|
15 |
- because they do not have practical security implications. |
|
16 |
- |
|
17 |
-[INTERCHANGABLE_PASSPHRASES]: ../explanation/faq-vault-interchangable-passphrases.md |
... | ... |
@@ -1,10 +0,0 @@ |
1 |
-### Added |
|
2 |
- |
|
3 |
- - Beyond [`bytes`][] and [`bytearray`][], |
|
4 |
- [`Vault`][derivepassphrase.vault.Vault] objects now accept arbitrary |
|
5 |
- [Buffer][collections.abc.Buffer] objects as passphrases or service |
|
6 |
- names. |
|
7 |
- - [`Vault`][derivepassphrase.vault.Vault] objects now expose [the vault |
|
8 |
- UUID][derivepassphrase.vault.Vault.UUID] and [the character |
|
9 |
- sets][derivepassphrase.vault.Vault.CHARSETS] as public attributes. |
|
10 |
- |
... | ... |
@@ -1,8 +0,0 @@ |
1 |
-### Changed |
|
2 |
- |
|
3 |
- - The test suite now uses a different feature matrix and different |
|
4 |
- [hypothesis][] profiles. |
|
5 |
- The slowdown caused by coverage measurement is now more accurately |
|
6 |
- estimated and adjusted for in the [hypothesis][] settings. |
|
7 |
- |
|
8 |
-[hypothesis]: https://pypi.org/project/hypothesis/ |
... | ... |
@@ -1,10 +0,0 @@ |
1 |
-### Changed |
|
2 |
- |
|
3 |
- - The test suite has been cleaned up, partly reorganized, and |
|
4 |
- rudimentarily documented. |
|
5 |
- Several new [hypothesis][]-based tests were also added, particularly to |
|
6 |
- test the core assumptions of the [vault][derivepassphrase.vault] |
|
7 |
- derivation scheme about sensitivity (or lack thereof) to its inputs and |
|
8 |
- its input formats. |
|
9 |
- |
|
10 |
-[hypothesis]: https://pypi.org/project/hypothesis/ |
... | ... |
@@ -1,14 +0,0 @@ |
1 |
-### Fixed |
|
2 |
- |
|
3 |
- - When exporting a vault configuration, `derivepassphrase vault` now |
|
4 |
- exports a pretty-printed configuration, to ease debugging and |
|
5 |
- introspection. ([#20]) |
|
6 |
- |
|
7 |
-### Changed |
|
8 |
- |
|
9 |
- - `derivepassphrase vault` stores its `vault.json` data file in |
|
10 |
- pretty-printed form. This is a stopgap measure to ease debugging and |
|
11 |
- introspection until better built-in query functionality for the effective |
|
12 |
- configuration is available, because users should not be rewarded. ([#20]) |
|
13 |
- |
|
14 |
-[#20]: https://github.com/the-13th-letter/derivepassphrase/issues/20 |
... | ... |
@@ -1,41 +0,0 @@ |
1 |
-### Added |
|
2 |
- |
|
3 |
- - `derivepassphrase vault` now supports selecting the editor interface |
|
4 |
- when editing notes via the `--modern-editor-interface` and |
|
5 |
- `--vault-legacy-editor-interface` options. |
|
6 |
- |
|
7 |
- - `derivepassphrase vault` now supports printing the service notes before |
|
8 |
- the passphrase, as an alternative, instead of always printing them |
|
9 |
- *after* the passphrase. |
|
10 |
- |
|
11 |
- - The tests concerning `derivepassphrase vault` and `--notes` usage have |
|
12 |
- been rewritten into [hypothesis][]-based tests where feasible. |
|
13 |
- |
|
14 |
-[hypothesis]: https://pypi.org/project/hypothesis/ |
|
15 |
- |
|
16 |
-### Changed |
|
17 |
- |
|
18 |
- - `derivepassphrase vault` now correctly requires the `--config` option in |
|
19 |
- addition to the `--notes` option to request that the service notes be |
|
20 |
- edited, for compatibility with vault(1). `notes` is now also a valid |
|
21 |
- setting name for `--unset` to take. Furthermore, editing the notes |
|
22 |
- successfully in any way, including no-op edits, will register the |
|
23 |
- service name as a known service to `derivepassphrase vault`, even if the |
|
24 |
- settings are otherwise empty. Finally, using plain `--notes` without |
|
25 |
- `--config` has no effect, and issues a warning to that extent. |
|
26 |
- |
|
27 |
- - `derivepassphrase vault` by default now uses an editor interface that |
|
28 |
- matches vault(1): the contents of the edited text file are used directly |
|
29 |
- as the service notes, without interpretation. Previously, we |
|
30 |
- post-processed the text file to remove comments and our instruction |
|
31 |
- texts, and interpreted an empty file as a request to abort the edit. |
|
32 |
- These two editor interfaces ("legacy" and "modern") can be explicitly |
|
33 |
- selected, and for the legacy interface, which is less resilient against |
|
34 |
- data entry or usage errors, a backup copy of the old notes content is |
|
35 |
- made. |
|
36 |
- |
|
37 |
-### Fixed |
|
38 |
- |
|
39 |
- - `derivepassphrase vault` now also prints the service notes (if any) when |
|
40 |
- deriving a service passphrase, just like vault(1) does. |
|
41 |
- |
... | ... |
@@ -1,17 +0,0 @@ |
1 |
-### Added |
|
2 |
- |
|
3 |
- - The `derivepassphrase` source tree now contains scripts to ensure |
|
4 |
- consistent code quality: automatic linting, formatting and type |
|
5 |
- checking, and optional running of the test suite and building of the |
|
6 |
- documentation. The master quality control script doubles as a |
|
7 |
- servicable "pre-commit" hook for git. |
|
8 |
- |
|
9 |
-### Fixed |
|
10 |
- |
|
11 |
- - Instead of having to do this by hand, `derivepassphrase` now includes |
|
12 |
- build machinery to ensure consistency of its version number and its |
|
13 |
- diagnostic messages between the documentation and the code. |
|
14 |
- |
|
15 |
- (The canonical way to get the version number is the |
|
16 |
- [`importlib.metadata.version`][] standard library interface.) |
|
17 |
- |
... | ... |
@@ -1,9 +0,0 @@ |
1 |
-### Added |
|
2 |
- |
|
3 |
- - The `--version` option of `derivepassphrase` and each subcommand |
|
4 |
- additionally reports build and environment information, such as |
|
5 |
- supported subcommands, derivation schemes, foreign configuration formats |
|
6 |
- and active [PEP 508 extras][PEP_508]. Each subcommand only reports the |
|
7 |
- items relevant to that subcommand. |
|
8 |
- |
|
9 |
-[PEP_508]: https://peps.python.org/pep-0508/ |
... | ... |
@@ -1,10 +0,0 @@ |
1 |
-### Fixed |
|
2 |
- |
|
3 |
- - `derivepassphrase` now tests its locking implementation for correctness, |
|
4 |
- on both sides of the API. Specifically, we test that the respective |
|
5 |
- platform-specific locking primitives provide the requested mutual |
|
6 |
- exclusion properties, and we also test that the locking system as |
|
7 |
- a whole, when given functioning locking primitives, correctly serializes |
|
8 |
- access to the facilities it is supposed to guard. |
|
9 |
- |
|
10 |
-[#23]: https://github.com/the-13th-letter/derivepassphrase/issues/23 |
... | ... |
@@ -1,17 +0,0 @@ |
1 |
-### Fixed |
|
2 |
- |
|
3 |
- - `derivepassphrase` has been successfully tested on <abbr |
|
4 |
- title="Microsoft Windows">The Annoying OS</abbr>[^the-annoying-os] in |
|
5 |
- its baseline version, i.e., without SSH agent functionality but with |
|
6 |
- `cryptography` support. All incompatibilities in the test suite were |
|
7 |
- fixed if essential and/or feasible, or documented as skips or expected |
|
8 |
- failures if neither. |
|
9 |
- |
|
10 |
- (The latter case currently only concerns one single test that is |
|
11 |
- supposed to trigger OS errors while attempting to read the |
|
12 |
- `derivepassphrase` configuration files. <abbr title="Microsoft |
|
13 |
- Windows">The Annoying OS</abbr> happily returns an empty file instead.) |
|
14 |
- |
|
15 |
-[^the-annoying-os]: Hat tip---and apologies---to |
|
16 |
- [Timothée Mazzucotelli (`@pawamoy`)](https://github.com/pawamoy/) for |
|
17 |
- the fitting terminology. |
... | ... |
@@ -1,12 +0,0 @@ |
1 |
-### Removed |
|
2 |
- |
|
3 |
- - `derivepassphrase` no longer supports (automatic) colored output or |
|
4 |
- output with embedded text styling. There exist pseudo-standards (the |
|
5 |
- `NO_COLOR` and `FORCE_COLOR` environment variables) governing how to |
|
6 |
- influence this automatic detection, but they are under-specified with |
|
7 |
- regard to their interaction with each other. Until a consensus is |
|
8 |
- reached and automatic colored/styled output can be requested or rejected |
|
9 |
- reliably across different terminal programs, `derivepassphrase` will |
|
10 |
- rather emit only uncolored, unstyled, lowest-common-denominator |
|
11 |
- device-independent output. |
|
12 |
- |
... | ... |
@@ -44,6 +44,196 @@ |
44 | 44 |
|
45 | 45 |
<!-- scriv changelog start --> |
46 | 46 |
|
47 |
+## 0.5 (2025-06-14) {#v0.5} |
|
48 |
+ |
|
49 |
+### Removed {#removed-in-v0.5} |
|
50 |
+ |
|
51 |
+ - `derivepassphrase` no longer supports (automatic) colored output or |
|
52 |
+ output with embedded text styling. There exist pseudo-standards (the |
|
53 |
+ `NO_COLOR` and `FORCE_COLOR` environment variables) governing how to |
|
54 |
+ influence this automatic detection, but they are under-specified with |
|
55 |
+ regard to their interaction with each other. Until a consensus is |
|
56 |
+ reached and automatic colored/styled output can be requested or rejected |
|
57 |
+ reliably across different terminal programs, `derivepassphrase` will |
|
58 |
+ rather emit only uncolored, unstyled, lowest-common-denominator |
|
59 |
+ device-independent output. |
|
60 |
+ |
|
61 |
+### Added {#added-in-v0.5} |
|
62 |
+ |
|
63 |
+ - [`Vault`][derivepassphrase.vault.Vault] now can report on whether two |
|
64 |
+ master passphrases are interchangable with respect to the service |
|
65 |
+ passphrases they can derive. |
|
66 |
+ This is an artefact of how the master passphrase is converted to the |
|
67 |
+ random bit sequence with which the service passphrases are generated. |
|
68 |
+ See the corresponding [FAQ entry: What are "interchangable passphrases" |
|
69 |
+ in vault?][INTERCHANGABLE_PASSPHRASES] for details, including the |
|
70 |
+ practical security (non-)implications. |
|
71 |
+ |
|
72 |
+ The `derivepassphrase vault` command-line interface does not address |
|
73 |
+ this in any manner, mostly because the "non-standard" interchangable |
|
74 |
+ variants of a given master password tend to be ugly to type in, and |
|
75 |
+ because they do not have practical security implications. |
|
76 |
+ |
|
77 |
+ - Beyond [`bytes`][] and [`bytearray`][], |
|
78 |
+ [`Vault`][derivepassphrase.vault.Vault] objects now accept arbitrary |
|
79 |
+ [Buffer][collections.abc.Buffer] objects as passphrases or service |
|
80 |
+ names. |
|
81 |
+ |
|
82 |
+ - [`Vault`][derivepassphrase.vault.Vault] objects now expose [the vault |
|
83 |
+ UUID][derivepassphrase.vault.Vault.UUID] and [the character |
|
84 |
+ sets][derivepassphrase.vault.Vault.CHARSETS] as public attributes. |
|
85 |
+ |
|
86 |
+ - `derivepassphrase vault` now supports selecting the editor interface |
|
87 |
+ when editing notes via the `--modern-editor-interface` and |
|
88 |
+ `--vault-legacy-editor-interface` options. |
|
89 |
+ |
|
90 |
+ - `derivepassphrase vault` now supports printing the service notes before |
|
91 |
+ the passphrase, as an alternative, instead of always printing them |
|
92 |
+ *after* the passphrase. |
|
93 |
+ |
|
94 |
+ - The tests concerning `derivepassphrase vault` and `--notes` usage have |
|
95 |
+ been rewritten into [hypothesis][]-based tests where feasible. |
|
96 |
+ |
|
97 |
+ - The `derivepassphrase` source tree now contains scripts to ensure |
|
98 |
+ consistent code quality: automatic linting, formatting and type |
|
99 |
+ checking, and optional running of the test suite and building of the |
|
100 |
+ documentation. The master quality control script doubles as a |
|
101 |
+ servicable "pre-commit" hook for git. |
|
102 |
+ |
|
103 |
+ - The `--version` option of `derivepassphrase` and each subcommand |
|
104 |
+ additionally reports build and environment information, such as |
|
105 |
+ supported subcommands, derivation schemes, foreign configuration formats |
|
106 |
+ and active [PEP 508 extras][PEP_508]. Each subcommand only reports the |
|
107 |
+ items relevant to that subcommand. |
|
108 |
+ |
|
109 |
+[INTERCHANGABLE_PASSPHRASES]: ../explanation/faq-vault-interchangable-passphrases.md |
|
110 |
+[PEP_508]: https://peps.python.org/pep-0508/ |
|
111 |
+[hypothesis]: https://pypi.org/project/hypothesis/ |
|
112 |
+ |
|
113 |
+### Changed {#changed-in-v0.5} |
|
114 |
+ |
|
115 |
+ - The export handlers for "storeroom" and "vault-native" configuration |
|
116 |
+ data, |
|
117 |
+ [`export_storeroom_data`][derivepassphrase.exporter.storeroom.export_storeroom_data] |
|
118 |
+ and |
|
119 |
+ [`export_vault_native_data`][derivepassphrase.exporter.vault_native.export_vault_native_data] |
|
120 |
+ configuration data now both support a unified interface: |
|
121 |
+ [`ExportVaultConfigDataFunction`][derivepassphrase.exporter.ExportVaultConfigDataFunction]. |
|
122 |
+ A new dispatch function |
|
123 |
+ [`export_vault_config_data`][derivepassphrase.exporter.export_vault_config_data] |
|
124 |
+ automatically calls the correct backend, based on the requested format. |
|
125 |
+ |
|
126 |
+ This is a **breaking API change** due to the change in function |
|
127 |
+ parameter names and return types. |
|
128 |
+ |
|
129 |
+ - `KeyCommentPair` from [`derivepassphrase._types`][], and `KeyPair` and |
|
130 |
+ `MasterKeys` from [`derivepassphrase.exporter.storeroom`][], have been |
|
131 |
+ converted to [`NamedTuple`s][typing.NamedTuple] and renamed to |
|
132 |
+ [`SSHKeyCommentPair`][derivepassphrase._types.SSHKeyCommentPair], |
|
133 |
+ [`StoreroomKeyPair`][derivepassphrase._types.StoreroomKeyPair] and |
|
134 |
+ [`StoreroomMasterKeys`][derivepassphrase._types.StoreroomMasterKeys], |
|
135 |
+ respectively, in the [`derivepassphrase._types`][] module. |
|
136 |
+ |
|
137 |
+ This is a **breaking API change**. |
|
138 |
+ |
|
139 |
+ - Move the non-essential content of the [`derivepassphrase.cli`][] module |
|
140 |
+ into the "internals" subpackage. |
|
141 |
+ |
|
142 |
+ This is a **breaking API change** due to the removal of most functions |
|
143 |
+ from the [`derivepassphrase.cli`][] module. |
|
144 |
+ |
|
145 |
+ - The test suite now uses a different feature matrix and different |
|
146 |
+ [hypothesis][] profiles. |
|
147 |
+ The slowdown caused by coverage measurement is now more accurately |
|
148 |
+ estimated and adjusted for in the [hypothesis][] settings. |
|
149 |
+ |
|
150 |
+ - The test suite has been cleaned up, partly reorganized, and |
|
151 |
+ rudimentarily documented. |
|
152 |
+ Several new [hypothesis][]-based tests were also added, particularly to |
|
153 |
+ test the core assumptions of the [vault][derivepassphrase.vault] |
|
154 |
+ derivation scheme about sensitivity (or lack thereof) to its inputs and |
|
155 |
+ its input formats. |
|
156 |
+ |
|
157 |
+ - `derivepassphrase vault` stores its `vault.json` data file in |
|
158 |
+ pretty-printed form. This is a stopgap measure to ease debugging and |
|
159 |
+ introspection until better built-in query functionality for the effective |
|
160 |
+ configuration is available, because users should not be rewarded. ([#20]) |
|
161 |
+ |
|
162 |
+ - `derivepassphrase vault` now correctly requires the `--config` option in |
|
163 |
+ addition to the `--notes` option to request that the service notes be |
|
164 |
+ edited, for compatibility with vault(1). `notes` is now also a valid |
|
165 |
+ setting name for `--unset` to take. Furthermore, editing the notes |
|
166 |
+ successfully in any way, including no-op edits, will register the |
|
167 |
+ service name as a known service to `derivepassphrase vault`, even if the |
|
168 |
+ settings are otherwise empty. Finally, using plain `--notes` without |
|
169 |
+ `--config` has no effect, and issues a warning to that extent. |
|
170 |
+ |
|
171 |
+ - `derivepassphrase vault` by default now uses an editor interface that |
|
172 |
+ matches vault(1): the contents of the edited text file are used directly |
|
173 |
+ as the service notes, without interpretation. Previously, we |
|
174 |
+ post-processed the text file to remove comments and our instruction |
|
175 |
+ texts, and interpreted an empty file as a request to abort the edit. |
|
176 |
+ These two editor interfaces ("legacy" and "modern") can be explicitly |
|
177 |
+ selected, and for the legacy interface, which is less resilient against |
|
178 |
+ data entry or usage errors, a backup copy of the old notes content is |
|
179 |
+ made. |
|
180 |
+ |
|
181 |
+[#20]: https://github.com/the-13th-letter/derivepassphrase/issues/20 |
|
182 |
+[hypothesis]: https://pypi.org/project/hypothesis/ |
|
183 |
+ |
|
184 |
+### Fixed {#fixed-in-v0.5} |
|
185 |
+ |
|
186 |
+ - Shell completion for `zsh` was misbehaving in the presence of colons in |
|
187 |
+ the completion item. |
|
188 |
+ This was due to an overzealous workaround for |
|
189 |
+ [`pallets/click#2703`][CLICK_2703]. |
|
190 |
+ |
|
191 |
+ - When exporting a vault configuration, `derivepassphrase vault` now |
|
192 |
+ exports a pretty-printed configuration, to ease debugging and |
|
193 |
+ introspection. ([#20]) |
|
194 |
+ |
|
195 |
+ - `derivepassphrase vault` now also prints the service notes (if any) when |
|
196 |
+ deriving a service passphrase, just like vault(1) does. |
|
197 |
+ |
|
198 |
+ - Instead of having to do this by hand, `derivepassphrase` now includes |
|
199 |
+ build machinery to ensure consistency of its version number and its |
|
200 |
+ diagnostic messages between the documentation and the code. |
|
201 |
+ |
|
202 |
+ (The canonical way to get the version number is the |
|
203 |
+ [`importlib.metadata.version`][] standard library interface.) |
|
204 |
+ |
|
205 |
+ - `derivepassphrase` now locks its internals and its configuration against |
|
206 |
+ concurrent modifications. ([#22]) |
|
207 |
+ |
|
208 |
+ - Test `derivepassphrase` against PyPy 3.11. |
|
209 |
+ |
|
210 |
+ - `derivepassphrase` now tests its locking implementation for correctness, |
|
211 |
+ on both sides of the API. Specifically, we test that the respective |
|
212 |
+ platform-specific locking primitives provide the requested mutual |
|
213 |
+ exclusion properties, and we also test that the locking system as |
|
214 |
+ a whole, when given functioning locking primitives, correctly serializes |
|
215 |
+ access to the facilities it is supposed to guard. |
|
216 |
+ |
|
217 |
+ - `derivepassphrase` has been successfully tested on <abbr |
|
218 |
+ title="Microsoft Windows">The Annoying OS</abbr>[^the-annoying-os] in |
|
219 |
+ its baseline version, i.e., without SSH agent functionality but with |
|
220 |
+ `cryptography` support. All incompatibilities in the test suite were |
|
221 |
+ fixed if essential and/or feasible, or documented as skips or expected |
|
222 |
+ failures if neither. |
|
223 |
+ |
|
224 |
+ (The latter case currently only concerns one single test that is |
|
225 |
+ supposed to trigger OS errors while attempting to read the |
|
226 |
+ `derivepassphrase` configuration files. <abbr title="Microsoft |
|
227 |
+ Windows">The Annoying OS</abbr> happily returns an empty file instead.) |
|
228 |
+ |
|
229 |
+[^the-annoying-os]: Hat tip---and apologies---to |
|
230 |
+ [Timothée Mazzucotelli (`@pawamoy`)](https://github.com/pawamoy/) for |
|
231 |
+ the fitting terminology. |
|
232 |
+ |
|
233 |
+[#22]: https://github.com/the-13th-letter/derivepassphrase/issues/22 |
|
234 |
+[#23]: https://github.com/the-13th-letter/derivepassphrase/issues/23 |
|
235 |
+[CLICK_2703]: https://github.com/pallets/click/issues/2703 |
|
236 |
+ |
|
47 | 237 |
## 0.4.0 (2025-01-07) {#v0.4.0} |
48 | 238 |
|
49 | 239 |
### Added {#added-in-v0.4.0} |
50 | 240 |