From bec11291697bbcfc3c1eec4bbdd069ea5dba6378 Mon Sep 17 00:00:00 2001 From: Ivan Date: Thu, 23 Apr 2026 17:50:09 -0500 Subject: [PATCH] chore(release): bump version to 4.5.1 and update changelog --- CHANGELOG.md | 22 +++++++- README.md | 2 +- docs/meshchatx_on_raspberry_pi.md | 6 +-- lang/README.de.md | 2 +- lang/README.it.md | 2 +- lang/README.ja.md | 2 +- lang/README.ru.md | 2 +- lang/README.zh.md | 2 +- meshchatx/__init__.py | 2 +- meshchatx/meshchat.py | 5 +- .../src/backend/data/THIRD_PARTY_NOTICES.txt | 2 +- meshchatx/src/version.py | 2 +- package.json | 2 +- packaging/arch/PKGBUILD | 4 +- poetry.lock | 51 ++++++++----------- pyproject.toml | 2 +- tests/backend/test_app_status_tracking.py | 6 +-- tests/frontend/AppModals.test.js | 10 ++-- tests/frontend/ChangelogModal.test.js | 6 +-- 19 files changed, 73 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff67677..de14503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,27 @@ All notable changes to this project will be documented in this file. -## [4.5.0] - 2026-04-24 +## [4.5.1] - 2026-04-24 + +### Identity switching + +- **Hotswap API**: Identity switch responses now include **display name** and **identity hash** so the client can refresh state without guessing from partial payloads. +- **Event handling**: Identity switch events are **deduplicated** in **`App.vue`** and **`IdentitiesPage.vue`** so rapid or repeated signals do not stack duplicate work. +- **Locales**: Confirmation copy for switching identities no longer tells users to restart when that is not required (aligned strings across supported languages). +- **Tests**: New **HTTP** coverage for the identity switch API (success paths, validation, and error responses). + +### Desktop (Electron) + +- **Boot experience**: **Splash screen** on startup and **Codec2** loader scripts use **retry** logic so transient load failures are less likely to strand voice features. +- **Developer tools**: **F12** toggles **DevTools**; the menu bar **auto-hides** in main windows for a cleaner ui. +- **Content Security Policy**: CSP now allows **`wasm-unsafe-eval`** where needed so **WebAssembly** used by the stack (for example audio codec paths) can run under the hardened policy. + +### Microphone and translations + +- **Recording**: Microphone capture updates **error handling** and adjusts **AudioWorklet** import so failures surface more reliably instead of failing silently. +- **Locales**: New and updated strings for **microphone** errors so users get clearer guidance when capture or permissions go wrong. + +## [4.5.0] - 2026-04-23 ### TL;DR diff --git a/README.md b/README.md index 9d24ba9..d6ace5f 100644 --- a/README.md +++ b/README.md @@ -300,7 +300,7 @@ task build:all ## Versioning -Current version in this repo is `4.5.0`. +Current version in this repo is `4.5.1`. - `package.json` is the JavaScript/Electron version source. - `meshchatx/src/version.py` is synced from `package.json` using: diff --git a/docs/meshchatx_on_raspberry_pi.md b/docs/meshchatx_on_raspberry_pi.md index 94807d7..730dc33 100644 --- a/docs/meshchatx_on_raspberry_pi.md +++ b/docs/meshchatx_on_raspberry_pi.md @@ -61,17 +61,17 @@ source ~/.profile ## 3) Install MeshChatX with pipx (recommended) -Preferred option (recommended): install from a release wheel (4.5.0 or newer), +Preferred option (recommended): install from a release wheel (4.5.1 or newer), because the wheel bundles frontend assets. ```bash pipx install /path/to/reticulum_meshchatx--py3-none-any.whl ``` -Direct example (v4.5.0): +Direct example (v4.5.1): ```bash -pipx install "https://git.quad4.io/RNS-Things/MeshChatX/releases/download/v4.4.0/reticulum_meshchatx-4.5.0-py3-none-any.whl" +pipx install "https://git.quad4.io/RNS-Things/MeshChatX/releases/download/v4.5.1/reticulum_meshchatx-4.5.1-py3-none-any.whl" ``` `py3-none-any` wheels are architecture-independent, so the same wheel artifact diff --git a/lang/README.de.md b/lang/README.de.md index 0a5afcd..d785b81 100644 --- a/lang/README.de.md +++ b/lang/README.de.md @@ -295,7 +295,7 @@ task build:all ## Versionierung -Aktuelle Version in diesem Repository: `4.5.0`. +Aktuelle Version in diesem Repository: `4.5.1`. - `package.json` ist die Quelle fuer die JavaScript/Electron-Version. - `meshchatx/src/version.py` wird aus `package.json` synchronisiert mit: diff --git a/lang/README.it.md b/lang/README.it.md index 02ff385..ae79f94 100644 --- a/lang/README.it.md +++ b/lang/README.it.md @@ -295,7 +295,7 @@ Scorciatoie `Makefile`: ## Versioning -Versione attuale nel repository: `4.5.0`. +Versione attuale nel repository: `4.5.1`. - La fonte della versione JavaScript/Electron e `package.json`. - `meshchatx/src/version.py` e sincronizzato da `package.json` con: diff --git a/lang/README.ja.md b/lang/README.ja.md index 07ca3a7..3ab2ceb 100644 --- a/lang/README.ja.md +++ b/lang/README.ja.md @@ -295,7 +295,7 @@ task build:all ## バージョン管理 -このリポジトリの現在のバージョンは `4.5.0` です。 +このリポジトリの現在のバージョンは `4.5.1` です。 - JavaScript / Electron のバージョンソースは `package.json`。 - `meshchatx/src/version.py` は次で `package.json` と同期します: diff --git a/lang/README.ru.md b/lang/README.ru.md index 9b9bf0f..6e17743 100644 --- a/lang/README.ru.md +++ b/lang/README.ru.md @@ -295,7 +295,7 @@ task build:all ## Версионирование -Текущая версия в репозитории: `4.5.0`. +Текущая версия в репозитории: `4.5.1`. - Источник версии JS/Electron — `package.json`. - `meshchatx/src/version.py` синхронизируется из `package.json`: diff --git a/lang/README.zh.md b/lang/README.zh.md index c30145d..7ab6f2e 100644 --- a/lang/README.zh.md +++ b/lang/README.zh.md @@ -295,7 +295,7 @@ task build:all ## 版本 -本仓库当前版本: `4.5.0`。 +本仓库当前版本: `4.5.1`。 - JavaScript/Electron 版本以 `package.json` 为准。 - `meshchatx/src/version.py` 通过以下命令与 `package.json` 同步: diff --git a/meshchatx/__init__.py b/meshchatx/__init__.py index d3a3134..ecb9296 100644 --- a/meshchatx/__init__.py +++ b/meshchatx/__init__.py @@ -2,4 +2,4 @@ """Reticulum MeshChatX - A mesh network communications app.""" -__version__ = "4.5.0" +__version__ = "4.5.1" diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py index fef4220..33d4aed 100644 --- a/meshchatx/meshchat.py +++ b/meshchatx/meshchat.py @@ -11593,9 +11593,10 @@ class ReticulumMeshChat: if path.startswith("/reticulum-docs/") or path.startswith( "/rnode-flasher/" ): - script_sources = ["'self'", "'unsafe-inline'"] + script_sources = ["'self'", "'unsafe-inline'", "'wasm-unsafe-eval'"] else: - script_sources = ["'self'"] + # wasm-unsafe-eval: Codec2 / sox Emscripten WASM (sox.js) without full unsafe-eval + script_sources = ["'self'", "'wasm-unsafe-eval'"] style_sources = ["'self'", "'unsafe-inline'"] if self.current_context and self.current_context.config: diff --git a/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt b/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt index fc314fa..eb34c4e 100644 --- a/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt +++ b/meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt @@ -76,7 +76,7 @@ pycparser 3.0 pyserial 3.5 License: BSD Author: Chris Liechti -reticulum-meshchatx 4.5.0 +reticulum-meshchatx 4.5.1 License: 0BSD AND MIT Author: Quad4 rns 1.1.9 diff --git a/meshchatx/src/version.py b/meshchatx/src/version.py index 460b7af..a18bd84 100644 --- a/meshchatx/src/version.py +++ b/meshchatx/src/version.py @@ -3,4 +3,4 @@ Do not edit by hand. Run: pnpm run version:sync """ -__version__ = "4.5.0" +__version__ = "4.5.1" diff --git a/package.json b/package.json index 439d914..93e7590 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "reticulum-meshchatx", - "version": "4.5.0", + "version": "4.5.1", "description": "A simple mesh network communications app powered by the Reticulum Network Stack", "homepage": "https://git.quad4.io/RNS-Things/MeshChatX", "desktopName": "reticulum-meshchatx.desktop", diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index 9555bd9..ccdf36b 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Ivan pkgname=reticulum-meshchatx-git _pkgname=reticulum-meshchatx -pkgver=4.5.0.r0.gebacc00 +pkgver=4.5.1.r0.gebacc00 pkgrel=1 pkgdesc="A simple mesh network communications app powered by the Reticulum Network Stack" arch=('x86_64' 'aarch64') @@ -19,7 +19,7 @@ sha256sums=('SKIP' pkgver() { cd "$_pkgname" git describe --long --tags 2>/dev/null | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' || \ - printf "4.5.0.r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" + printf "4.5.1.r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" } prepare() { diff --git a/poetry.lock b/poetry.lock index fdde816..0980c2b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -470,15 +470,15 @@ pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "click" -version = "8.3.2" +version = "8.3.3" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.10" groups = ["dev"] markers = "python_version < \"4.0\"" files = [ - {file = "click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d"}, - {file = "click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5"}, + {file = "click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613"}, + {file = "click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2"}, ] [package.dependencies] @@ -1022,18 +1022,18 @@ zoneinfo = ["tzdata (>=2026.1) ; sys_platform == \"win32\" or sys_platform == \" [[package]] name = "idna" -version = "3.11" +version = "3.13" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, - {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, + {file = "idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3"}, + {file = "idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242"}, ] [package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "iniconfig" @@ -2142,32 +2142,25 @@ testing = ["filelock"] [[package]] name = "python-msilib" -version = "0.5.0" +version = "0.6.0" description = "Read and write Microsoft Installer files" optional = false python-versions = ">=3.13" groups = ["dev"] markers = "sys_platform == \"win32\" and python_version >= \"3.13\"" files = [ - {file = "python_msilib-0.5.0-cp313-cp313-win32.whl", hash = "sha256:240c9cebc402361e6fe32fb94020ce5a2674343122cb4dbd036fa59068d153c4"}, - {file = "python_msilib-0.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:cb1db6fa79cfff539a0f313c80f27760b3c452b8fb59878c4b1ce2959711541e"}, - {file = "python_msilib-0.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:3904771a9e31276da9d2de4e431e09b122a354b84b41746c6feaa14b91d2fd0d"}, - {file = "python_msilib-0.5.0-cp313-cp313t-win32.whl", hash = "sha256:67ab7fe107b6dbed42e609d0731ae9863c8aaf58e6015995e42671a9d215fe86"}, - {file = "python_msilib-0.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc3d895c1cb4f695344a7149909d460020d0e6f987d33ab40ea687d65dd1f2ad"}, - {file = "python_msilib-0.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:cc62a3d0500c1d6d21bea347c55215ae16c81bc749134c47e466f284a46b56fe"}, - {file = "python_msilib-0.5.0-cp314-cp314-win32.whl", hash = "sha256:e5023ab8da04a13769d1054e64415c02c198d442ce0f7cd9637204341d997379"}, - {file = "python_msilib-0.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:24cd942d097bafc97018698e1e66652143529eecaf8b8df55a624d580d81df7c"}, - {file = "python_msilib-0.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:f9da5045835d0de30b1087ff6fd6e0b6d076e248cd26405c0d399d8649ef9684"}, - {file = "python_msilib-0.5.0-cp314-cp314t-win32.whl", hash = "sha256:821a164e72d77786d9e6d7cd28c060e6668665632a29f2c76abac85651f05f11"}, - {file = "python_msilib-0.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3fafe94d66f00bd3b26159b7ff43078421738288af5212744a1cb4a1cea52bc8"}, - {file = "python_msilib-0.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1c0b7a595dd457f7df5bd102c4c5abe5337ba0362aab2ece31bea29e6e7d9f2d"}, - {file = "python_msilib-0.5.0.tar.gz", hash = "sha256:5d9d0c2af2cafbc50d484cce4cfab1cb8cfd65d705d7111d216bc525a059113b"}, + {file = "python_msilib-0.6.0-cp313-cp313-win32.whl", hash = "sha256:1145ce1e0eaf2af2948a02147415c621323cb2b2ff118fccdac333941547c11b"}, + {file = "python_msilib-0.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:41b83e39c622a79042b3d1745421ce3492b954d701d7aeaf942d974c31291431"}, + {file = "python_msilib-0.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:3ac47071f27755b11f9e01d7222c2babd84997410f4f0d96ded55c187b0b1fb8"}, + {file = "python_msilib-0.6.0-cp314-cp314-win32.whl", hash = "sha256:8144e6249d12768e08844672175404b21a1f7ce4b7b6d539858a4f9ad6d6ca6c"}, + {file = "python_msilib-0.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:281421203401afef589321f16d92d7aea8e5cf35f0345e47174346a3dde24808"}, + {file = "python_msilib-0.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:c2fbc0d9388c937222f2ef717385aade5a3696bdc3b81150a0098c0cb79b58b9"}, + {file = "python_msilib-0.6.0-cp314-cp314t-win32.whl", hash = "sha256:e511a1b4e247901416a39167090a5e58d1b65d1a5b401d0250dce983f4ab0980"}, + {file = "python_msilib-0.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:848e7dd1fc61407d207fa4a2b7ac12b3a2de376d394a1d3f70ac4034bc9cd1a9"}, + {file = "python_msilib-0.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a645358b02e17b0de61ea3f1dcd9f5d6b738148b1f317e2e864a08e04eeb80f3"}, + {file = "python_msilib-0.6.0.tar.gz", hash = "sha256:47a6c16aa8528b797bd81e71cc544505b5444543319dbaf12011123b750c9d3c"}, ] -[package.extras] -dev = ["bump-my-version (==1.2.4)", "cibuildwheel (==3.3.0)", "pre-commit (==4.5.0)"] -tests = ["coverage (==7.12.0)", "pytest (==9.0.2)"] - [[package]] name = "pyyaml" version = "6.0.3" @@ -2632,19 +2625,19 @@ files = [ [[package]] name = "striprtf" -version = "0.0.29" +version = "0.0.31" description = "A simple library to convert rtf to text" optional = false python-versions = ">=3.8" groups = ["dev"] markers = "sys_platform == \"win32\"" files = [ - {file = "striprtf-0.0.29-py3-none-any.whl", hash = "sha256:0fc6a41999d015358d19627776b616424dd501ad698105c81d76734d1e14d91b"}, - {file = "striprtf-0.0.29.tar.gz", hash = "sha256:5a822d075e17417934ed3add6fc79b5fc8fb544fe4370b2f894cdd28f0ddd78e"}, + {file = "striprtf-0.0.31-py3-none-any.whl", hash = "sha256:8ec8150a4213951675f711750a4a5b8a98a6da3ef85deeff0bb6e39cd2beeda4"}, + {file = "striprtf-0.0.31.tar.gz", hash = "sha256:ce4b6403427d7d5cda95fdb61365432225f6fbe5ea6797e1357f4045d351ba2d"}, ] [package.extras] -dev = ["build (>=1.0.0)", "pytest (>=7.0.0)"] +dev = ["build (>=1.0.0)", "pytest (>=7.0.0)", "twine (>=6.1.0)"] [[package]] name = "textual" diff --git a/pyproject.toml b/pyproject.toml index f1b3bb6..970d994 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "reticulum-meshchatx" -version = "4.5.0" +version = "4.5.1" description = "A simple mesh network communications app powered by the Reticulum Network Stack" authors = [ {name = "Quad4"} diff --git a/tests/backend/test_app_status_tracking.py b/tests/backend/test_app_status_tracking.py index ed4e858..d4c6d80 100644 --- a/tests/backend/test_app_status_tracking.py +++ b/tests/backend/test_app_status_tracking.py @@ -96,8 +96,8 @@ async def test_app_status_endpoints(mock_rns_minimal, temp_dir): app_instance.config.set("tutorial_seen", True) assert app_instance.config.get("tutorial_seen") == "true" - app_instance.config.set("changelog_seen_version", "4.5.0") - assert app_instance.config.get("changelog_seen_version") == "4.5.0" + app_instance.config.set("changelog_seen_version", "4.5.1") + assert app_instance.config.get("changelog_seen_version") == "4.5.1" # Test app_info returns these values with ExitStack() as info_stack: @@ -113,4 +113,4 @@ async def test_app_status_endpoints(mock_rns_minimal, temp_dir): assert val == "true" val = app_instance.config.get("changelog_seen_version") - assert val == "4.5.0" + assert val == "4.5.1" diff --git a/tests/frontend/AppModals.test.js b/tests/frontend/AppModals.test.js index 072a9e5..b915a34 100644 --- a/tests/frontend/AppModals.test.js +++ b/tests/frontend/AppModals.test.js @@ -62,9 +62,9 @@ describe("App.vue Modals", () => { return Promise.resolve({ data: { app_info: { - version: "4.5.0", + version: "4.5.1", tutorial_seen: true, - changelog_seen_version: "4.5.0", + changelog_seen_version: "4.5.1", }, }, }); @@ -94,7 +94,7 @@ describe("App.vue Modals", () => { return Promise.resolve({ data: { app_info: { - version: "4.5.0", + version: "4.5.1", tutorial_seen: false, changelog_seen_version: "0.0.0", }, @@ -153,7 +153,7 @@ describe("App.vue Modals", () => { return Promise.resolve({ data: { app_info: { - version: "4.5.0", + version: "4.5.1", tutorial_seen: true, changelog_seen_version: "3.9.0", }, @@ -161,7 +161,7 @@ describe("App.vue Modals", () => { }); } if (url === "/api/v1/app/changelog") { - return Promise.resolve({ data: { html: "

New Features

", version: "4.5.0" } }); + return Promise.resolve({ data: { html: "

New Features

", version: "4.5.1" } }); } if (url === "/api/v1/config") return Promise.resolve({ data: { config: { theme: "dark" } } }); if (url === "/api/v1/auth/status") return Promise.resolve({ data: { auth_enabled: false } }); diff --git a/tests/frontend/ChangelogModal.test.js b/tests/frontend/ChangelogModal.test.js index 65fd25c..339dffa 100644 --- a/tests/frontend/ChangelogModal.test.js +++ b/tests/frontend/ChangelogModal.test.js @@ -78,7 +78,7 @@ describe("ChangelogModal.vue", () => { axiosMock.get.mockResolvedValue({ data: { html: "

Test

", - version: "4.5.0", + version: "4.5.1", }, }); @@ -95,7 +95,7 @@ describe("ChangelogModal.vue", () => { axiosMock.get.mockResolvedValue({ data: { html: "

Test

", - version: "4.5.0", + version: "4.5.1", }, }); @@ -114,7 +114,7 @@ describe("ChangelogModal.vue", () => { axiosMock.get.mockResolvedValue({ data: { html: "

Test

", - version: "4.5.0", + version: "4.5.1", }, });