fix(meshcore): surface real Share Contact errors instead of failing silently#3481
Conversation
…ilently Share Contact did nothing on a MeshCore TCP Companion source with no actionable error (issue #3480). Root cause spans the chain: meshcore.js's shareContact() rejects with NO argument on a firmware Err and has no internal timeout, so the propagated error was the literal string "undefined" (or, with no firmware response, a 30s hang then a generic timeout). The manager returned a bare boolean, the route replied with a hardcoded 409 string, and the UI showed a hardcoded i18n string — so the real reason never reached the user. - Native backend: wrap c.shareContact() and convert the argument-less reject into an actionable message ("firmware may not support CMD_SHARE_CONTACT"). - Manager: shareContact() returns { ok, error } (ShareContactResult), uses a 10s dedicated timeout instead of the 30s default (fail fast, no hang), and maps timeout / "undefined" into firmware-support hints. - Route: forward the real error; 504 for no-response, 409 otherwise. - UI hook + panel: surface the server's error text instead of a generic string. Note: the underlying broadcast may still fail if the firmware (pymc / v1.15) doesn't implement CMD_SHARE_CONTACT — this makes that observable and fast rather than silent. Tests cover backend, manager, route, and panel layers. Fixes #3480 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @Yeraze's task —— View job PR Review: Share Contact Error Handling ImprovementsReview Checklist
Overall AssessmentThis is an excellent PR that addresses a significant UX issue (#3480) with a comprehensive, well-architected solution. The changes follow MeshMonitor's coding standards and demonstrate careful attention to error handling, testing, and user experience. ✅ Strengths1. Comprehensive Error Chain FixThe PR traces and fixes the entire error propagation chain from the lowest level (meshcore.js) to the UI:
2. Smart Timeout Strategy
3. Excellent Test Coverage
4. Type Safety & Structure
🔍 Technical DetailsError Handling Flow
Performance Improvements
|
Bump version to 4.10.4 across package.json, package-lock.json, helm/meshmonitor/Chart.yaml, desktop/package.json, and desktop/src-tauri/tauri.conf.json. Promote CHANGELOG [Unreleased] to [4.10.4] and add the user-facing fixes merged since 4.10.3: timed-events cross-source firing (#3479), module config save for Traffic Management/Status Message (#3464), Auto Favorites firmware-support cache (#3482), MeshCore Share Contact error surfacing (#3481), and the Firefox-Android delivered-icon CSS fix (#3477). The air-quality particle-count fix (#3483) was already in [Unreleased]. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Share Contact did nothing on a MeshCore TCP Companion source and gave the user no actionable error (issue #3480). I traced the full chain and the root cause is broader than the issue described:
meshcore.js'sshareContact()rejects with no argument on a firmwareErrand has no internal timeout (connection.js:1287), so the propagated error was the literal string"undefined"— or, if the firmware never replied, a 30s hang followed by a generic timeout. On top of that the manager returned a bareboolean, the route replied with a hardcoded 409 string, and the UI showed a hardcoded i18n string, so the real reason never reached the user.The device-type gate is not the cause — a TCP Companion correctly resolves to
COMPANION, and the on-wire frame (opcode 16 + 32-byte key) is correct. If the broadcast itself fails, that's almost certainly a firmware limitation (pymc / official v1.15 not implementingCMD_SHARE_CONTACT); this PR makes that observable and fast rather than silent, which is the actual complaint.Changes
meshcoreNativeBackend.ts): wrapc.shareContact()and convert the argument-lessreject()into an actionable error (withcause) instead of lettingString(undefined)propagate.meshcoreManager.ts):shareContact()now returns{ ok, error }(ShareContactResult), uses a 10s dedicated timeout instead of the 30s default (fail fast, no hang), and maps timeout /"undefined"into firmware-support hints.meshcoreRoutes.ts): forward the real error text — 504 for no-response, 409 otherwise.useMeshCore.tshook +MeshCoreContactDetailPanel.tsx): surface the server's error text instead of the hardcoded generic string.Issues Resolved
Fixes #3480.
Documentation Updates
No documentation changes needed — internal error-handling / diagnostics.
Testing
tsc --noEmit)meshcoreManager.shareContact.test.ts(6): return shape + short timeout, non-Companion, disconnected, timeout→hint,"undefined"→hint, verbatim forwardmeshcoreNativeBackend.test.ts(+2): success path + bare-reject()→actionable errormeshcoreRoutes.test.ts: updated mock shape; 409 forwards real error + new 504 timeout caseMeshCoreContactDetailPanel.test.tsx(+2): real error surfaced + generic fallback🤖 Generated with Claude Code