MeshMonitor v4.13.0
MeshMonitor 4.13.0 is the largest release of the 4.x line, stabilized through three release candidates. The headline is the Map Consolidation epic: every map surface — Dashboard, Nodes, Map Analysis, MeshCore, Unified, and embeds — now shares one rendering core, one layer library, and one popup family, so features and fixes land everywhere at once. On top of that come node selection and Follow mode, a distance-measurement tool, a polar grid overlay, and a long list of map interaction fixes. MeshCore gains message delete/purge, automatic send retries, Auto-Pathfinding target filtering, a configurable CLI timeout, and a completed Virtual Node command surface. Automations pick up multi-channel triggers, a scheduled device-reboot action, and per-source tapback routing. The long-standing "low-battery alerts silently never fire" bug — reported five separate times — is fixed at its root. Under the hood, a major architecture remediation unified the source-manager registry, moved fresh installs to migration-replay bootstrap, and deleted the legacy synchronous database API. Three deliberate breaking changes ship in this release: auto-upgrade is retired, TRUST_PROXY defaults to false, and source-scoped API endpoints require an explicit sourceId — see Upgrade Notes below. Docker users: :latest now only moves on stable releases like this one; RCs publish to :dev.
📖 Release announcement · Full changelog
Features
Maps
- Map Consolidation epic: shared BaseMap shell, layer library, unified node-marker factory, one popup family, canonical traceroute rendering on all maps including embeds — #4049, #4051, #4057, #4060, #4064, #4065, #4066, #4067, #4068 (epic #4047)
- Node selection, emphasis & Follow mode with auto-zoom on Map Analysis — #4010, #4012 (#3788)
- Node-to-node line-of-sight distance measurement tool on all maps — #4013 (#3636)
- Polar grid overlay (Map Analysis, Unified, MeshCore) — #3983, #4071 (#3971)
- Pan/zoom/spiderfy interaction polish: zoom clamp, scaled animations, zoom-gated spiderfy — #4072 (#4046)
MeshCore
- Delete/purge messages: per-message, per-conversation, purge-all — #3984 (#3981)
- Automatic DM retry via same-path + flood cadence; opt-in auto-retry for automated channel sends — #3980, #3988 (#3977, #3979)
- Auto-Pathfinding target filtering: allowlist, name regex, last-heard, hops, signal — #4039 (#4024)
- Configurable remote/local CLI reply timeout — #4033 (#4027), honored in VN relay via #4107
- Virtual Node: relay status requests & neighbour queries — #3991, #3993 (#3904)
- Collapsible node list for mobile map access — #4079
Automation
- Multi-channel message trigger OR-list — #3982 (#3974)
- Scheduled device-reboot action — #4002 (#3995)
- "Send via sources" selector on the tapback action — #3997 (#3996)
Other
- UDP Broadcast network setting (
enabled_protocols) exposed — #4113 (#4112) - Update-available notifications with per-deployment upgrade instructions (replaces auto-upgrade) — #4108
Bug Fixes
- Low-battery/inactive-node alerts lost to split per-source notification preferences — #4035 (#3417, #3462, #3671, #3884, #4020); leftover
UNIQUE(user_id)autoindex dropped — #4045 (#4044) - Map: popup/spiderfy decoupling + obscured-marker declutter on all maps — #4022, #4028 (#4015, #4016)
- Map: click no longer snaps view back or freezes interaction; wheel zoom, zoom-to-node, chunk-reload self-heal — #4071, #4080, #4082, #4098
- Map: Null Island / out-of-range positions filtered from markers and line endpoints — #4077, #4078, #4099, #4101, #4103
- Map: ROUTER_LATE renders as repeater tower — #4076 (#4075); tileset switch no longer remounts/flickers the raster layer — #4097
- Dashboard map: neighbor lines honor the configured map endpoint — #4055 (#4042), thanks @temalo
- MeshCore: automation DM triggers populate
fromName— #3978 (#3973); DM destinations resolve as pubkey strings — #4019 (#4018) - MeshCore: exact decrypt-and-match for "repeaters relayed" echo — #3987 (#3979); unscoped replies for unnameable trigger scopes — #4003 (#3998)
- MeshCore: danger-guard no longer fires on dotted config paths — #4029 (#4025); non-functional Stats quick-action removed — #4031 (#4026)
- MeshCore Virtual Node: boot race & listen-error zombie fixed — #4001 (#4000, #3975); login relays admin flag + firmware level — #4095 (#4094); CLI-type messages relay via CLI path — #4107 (#4106)
- Auth: proxy-auth auto-provisioning failed on pre-v3.7 SQLite databases (stale CHECK constraint) — #4120 (#4119)
- Permissions: virtual-channel
canReadgrants honored on all per-source read surfaces — #4116 (#4093) - Automation: multi-source resolution & test fixes — #4007, #4019
Security
TRUST_PROXYdefaults tofalse— direct clients can no longer spoofX-Forwarded-Forpast the login rate limiter — #3968- CSRF-token prefix and hot-path request details no longer logged to the browser console — #3970
- Process-level
unhandledRejection/uncaughtExceptionsafety net — #3967
Refactoring (remediation epic #3962)
- One unified source-manager registry (MeshCore included) — #4004, #4017; shared scheduler classes — #4005, #4009, #4014
- Fresh installs bootstrap via migration replay;
createTables()deleted; schema-drift tripwire — #3992, #4034, #4040, #4041 - Legacy sync database API deleted;
misc.tssplit into domain repositories — #4023, #4030, #4032, #4036, #4043, #4048 { success, error, code }response envelope helpers — #3990; fail-closed source scoping — #3976- Route-test harness with real auth middleware — #3986; lint ratchet (CI lint now blocking) — #3972, #3989, #3985
- Source-scoped API hardening:
sourceIdrequired on per-source endpoints — #4053, #4054, #4056, #4058, #4059, #4061, #4062, #4063
CI / DevOps
- Docker tags: pre-releases publish
:dev;:latestreserved for stable — #4102 - Log volume trimmed: routine activity moved to
debug, newtracetier, message bodies redacted — #3994 - System tests: sourceId wiring + retired-endpoint expectations — #4052, #4069, #4121
- 4.13 documentation refresh: source-scoped API, release tracks, updating guide, blog — #4105, #3966
Removed
- In-app Auto-Upgrade retired — watchdog sidecar, upgrade endpoints (now
410 FEATURE_RETIRED), and the Settings panel removed; update notifications remain — #4108
Dependencies & Translations
- Production group (9 updates),
helmet,protobufjs,lucide-react,re2, TypeScript/ESLint toolchain;meshcore.jsfork pinned to SHA — #3969, #4083–#4092 - Translations from Hosted Weblate — #4006
Issues Resolved
#3636, #3788, #3963, #3971, #3973, #3974, #3975, #3977, #3979, #3981, #3995, #3996, #3998, #4000, #4015, #4016, #4018, #4020, #4024, #4025, #4026, #4027, #4042, #4044, #4046, #4047, #4075, #4093, #4094, #4106, #4112, #4119
Upgrade Notes
Three deliberate breaking changes — please review before upgrading:
- Auto-Upgrade is retired. If you used the upgrade sidecar: remove
docker-compose.upgrade.ymlfrom your compose command,docker rm -f meshmonitor-upgrader, and dropAUTO_UPGRADE_ENABLED. For unattended updates use Watchtower. Full checklist: Updating MeshMonitor. - Behind a reverse proxy? Set
TRUST_PROXYexplicitly (e.g.TRUST_PROXY=1for one proxy hop). It now defaults tofalse; without it, proxied deployments will rate-limit logins by the proxy's IP. - API consumers: source-scoped endpoints require
sourceId. The bundled UI is unaffected. External scripts should consult the API source-scoping guide.
Docker users tracking release candidates: switch to the :dev tag — :latest now only moves on stable releases.
Thanks to @temalo for the Dashboard neighbor-lines fix, and to everyone who filed the detailed bug reports this release is built on. 🎉
Full Changelog: v4.12.5...v4.13.0
🚀 MeshMonitor v4.13.0
📦 Installation
Docker (recommended):
docker run -d \
--name meshmonitor \
-p 8080:3001 \
-v meshmonitor-data:/data \
ghcr.io/Yeraze/meshmonitor:4.13.0🧪 Testing
✅ All tests passed
✅ TypeScript checks passed
✅ Docker images built for linux/amd64, linux/arm64, linux/arm/v7
📋 Changes
See commit history for detailed changes.