fix(messaging): expose isUnmessagable/isLicensed so the DM UI hides for unmessagable nodes (#3755)#3766
Conversation
…or unmessagable nodes (#3755) mapDbNodeToDeviceInfo dropped the is_unmessagable / is_licensed columns (added in migration 101) when building the client node object, so every node reached the frontend with isUnmessagable === undefined. The DM guards in NodesTab (hide the DM button) and MessagesTab (lock the composer) therefore failed open for remote Meshtastic nodes — only the local node, which flows through a separate owner/identity path, worked. Pass both flags through the mapper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011JEaCGwY9Wz8jeV4e22GW4
|
Claude finished @Yeraze's task —— View job PR ReviewTasks:
SummaryThis is a clean, minimal fix for a genuine security-adjacent bug (DM UI failing open). The approach is correct and consistent with the existing codebase patterns. A few observations: Implementation (
|
|
Thanks! Agreed on the |
Summary
Fixes #3755. The DM UI did not hide for Meshtastic nodes that have the unmessagable bit set — the DM button still appeared in the Nodes tab and the message composer stayed writable, despite the node's intent to not receive direct messages.
Root cause
is_unmessagable/is_licensedare stored on thenodestable (migration 101, #3684), butmapDbNodeToDeviceInfo()— which builds the node object the API returns — never copied them onto the client object (it handlesisFavorite,isIgnored, etc., but not these two). So every node reached the frontend withisUnmessagable === undefined, and the two UI guards fail open:NodesTab.tsx— DM button shown when!node.isUnmessagable→ always shownMessagesTab.tsx— composer set read-only whenisUnmessagable === true→ neverOnly the local node worked, because its flag flows through a separate owner/identity endpoint, not the node list.
Fix
Pass
isUnmessagableandisLicensedthroughmapDbNodeToDeviceInfo(), mirroring the existingisIgnoredhandling.Testing
meshtasticManager.unmessagable.test.ts— 3 cases: flag1→ exposedtrue,0→ exposedfalse,null(legacy rows) → omitted./api/nodesnow returnsisUnmessagable: truefor the 36 nodes that carry the bit (previouslynullfor all).tscclean.🤖 Generated with Claude Code