feat(meshcore): channel CRUD + connect-time sync (phase 1/3)#3034
Conversation
Wires the meshcore.js channel API into MeshCoreManager and mirrors the device's channel list into the shared `channels` table on connect. Backend - meshcoreNativeBackend.ts: bridge-shaped get_channels / set_channel / delete_channel commands. set_channel validates idx range and that the hex-encoded secret decodes to exactly 16 bytes. - meshcoreManager.ts: listChannels / setChannel / deleteChannel / syncChannelsFromDevice. Sync runs after refreshContacts on the Companion connect path; failure is non-fatal. AES-128 secrets are stored as base64 in the existing `channels.psk` column; Meshtastic- only fields (role, uplinkEnabled, downlinkEnabled, positionPrecision) are explicitly null for MeshCore rows. - channels.ts repository: cleanupInvalidChannels is now source-type- aware. The 0–7 slot cap is a Meshtastic-only convention; MeshCore devices report a device-dependent number of channels. Channels owned by a MeshCore source are exempt; Meshtastic-owned and legacy NULL- sourceId rows still get the cap applied. Tests (+17) - meshcoreNativeBackend.test.ts: get_channels mapping, set_channel validation (idx range, 16-byte secret), delete_channel pass-through. - meshcoreManager.channels.test.ts (new file): listChannels, setChannel + deleteChannel re-sync behaviour, syncChannelsFromDevice upsert shape + sourceId scoping + empty-secret handling. - channels.test.ts (repository): new "preserves out-of-range channels owned by a MeshCore source" case. Existing tests now also create a sources table for the cleanupInvalidChannels JOIN. No schema migration required (reuses existing channels columns). This is phase 1 of 3 (see docs/meshcore-channels-plan.md): phase 2 = MeshCoreChannelsView reads the synced list, phase 3 = Configuration UI for create/edit/delete. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @Yeraze's task —— View job PR Review: MeshCore Channels Phase 1Comprehensive review completed. This is a well-implemented Phase 1 that establishes a solid foundation for MeshCore channel management. ✅ StrengthsArchitecture & Design
Implementation Quality
Test Coverage
🔍 Security AssessmentAcceptable Risks
Good Security Practices
⚡ Performance ConsiderationsEfficient Design
Future Considerations
🐛 No Significant Issues Found
📝 Minor Suggestions
🎯 Phase 1 Acceptance Criteria Met✅ Backend channel CRUD methods implemented Final Recommendation: ✅ APPROVEThis PR successfully delivers Phase 1 with high code quality, proper testing, and no significant issues. The architecture sets up Phases 2 and 3 well. Ready to merge. |
System Test ResultsMeshMonitor System Test ResultsTest Run: 2026-05-15 18:15:20 EDT Test Summary
✅ Overall Result: PASSEDAll deployment configurations are working correctly! Test DetailsConfiguration Import:
Quick Start Test:
Security Test:
V1 API Test:
Reverse Proxy Test:
Reverse Proxy + OIDC Test:
Virtual Node CLI Test:
Backup & Restore Test:
Database Migration Test:
DB Backing Consistency Test:
|
CI on PR #3034 failed the new "preserves out-of-range channels owned by a MeshCore source" test on the PostgreSQL backend: error: column "sourceid" of relation "channels" does not exist PostgreSQL folds unquoted identifiers to lowercase; the schema defines the column as "sourceId" (quoted), so the raw INSERT also needs the quotes. SQLite is identifier-case-insensitive and the original test worked there. MySQL's default sql_mode treats "..." as a string literal rather than a delimited identifier, so the column reference must stay bare for that backend. Branches the column reference by backend.dbType. SQLite + PG + MySQL now all pass the test locally; verified PG against a fresh postgres:16 container. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @Yeraze's task —— View job PR Review: MeshCore Channels Phase 1Comprehensive review completed. This is a well-implemented Phase 1 that establishes a solid foundation for MeshCore channel management. ✅ StrengthsArchitecture & Design
Implementation Quality
Test Coverage
🔍 Security AssessmentAcceptable Risks
Good Security Practices
⚡ Performance ConsiderationsEfficient Design
Future Considerations
🐛 No Significant Issues Found
📝 Minor Suggestions
🎯 Phase 1 Acceptance Criteria Met✅ Backend channel CRUD methods implemented Final Recommendation: ✅ APPROVEThis PR successfully delivers Phase 1 with high code quality, proper testing, and no significant issues. The architecture sets up Phases 2 and 3 well. Ready to merge. |
System Test ResultsMeshMonitor System Test ResultsTest Run: 2026-05-15 19:13:30 EDT Test Summary
✅ Overall Result: PASSEDAll deployment configurations are working correctly! Test DetailsConfiguration Import:
Quick Start Test:
Security Test:
V1 API Test:
Reverse Proxy Test:
Reverse Proxy + OIDC Test:
Virtual Node CLI Test:
Backup & Restore Test:
Database Migration Test:
DB Backing Consistency Test:
|
Bumps the version across all five canonical files (package.json, package-lock.json, helm/meshmonitor/Chart.yaml, desktop/src-tauri/tauri.conf.json, desktop/package.json) for the 4.5.2 release. Headline: MeshCore channel support is the major feature in this release. - Phase 1 (#3034) — MeshCoreManager exposes listChannels / setChannel / deleteChannel and mirrors the device's channel list into the shared `channels` table on connect. - Phase 2 (#3038) — MeshCoreChannelsView renders one tab per channel from the synced list; the send path is channel-idx aware. - Phase 3 (#3039) — Configuration UI adds, edits, regenerates the secret of, and deletes channels on the device; PUT/DELETE /api/channels/:id route writes through to MeshCore via the correct registry. - Polish (#3040) — empty-slot filter (the MAX_CHANNELS=40 leak), DB reconcile for stale empty rows, DM-view filters out channel pseudo-pubkeys and the local node from the peer sidebar. Also includes the per-node position-precision fix (#3033) from this release window. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 1 of 3 for MeshCore channels support. See
docs/meshcore-channels-plan.mdfor the full plan.Summary
Wires meshcore.js's channel API (
getChannels/setChannel/deleteChannel) intoMeshCoreManagerand mirrors the device's channel list into the sharedchannelstable on connect. Phases 2 and 3 (display + Configuration UI) are separate PRs.What changed
meshcoreNativeBackend.ts— three new bridge-shaped commands:get_channels,set_channel,delete_channel.set_channelvalidates idx range and that the hex-encoded secret decodes to exactly 16 bytes (AES-128).meshcoreManager.ts— publiclistChannels(),setChannel(idx, name, secretHex),deleteChannel(idx), plus a privatesyncChannelsFromDevice()that runs afterrefreshContactson the Companion connect path. Failure is non-fatal so a half-configured device still connects.channelsrepository —cleanupInvalidChannelsis now source-type aware. The 0–7 slot cap is a Meshtastic-only convention; MeshCore devices report a device-dependent number of channels. Channels owned by a MeshCore source are exempt; Meshtastic-owned and legacy NULL-sourceIdrows still get the cap applied.Why this design
channelstable, no schema migration. Shared fields (id,name,psk,sourceId) map 1:1 to MeshCore's{channelIdx, name, secret}. Meshtastic-only fields stayNULLfor MeshCore rows.pskcolumn. The wire/API form stays hex (matches the MeshCore CLI convention).Test plan
npx vitest run— 4943 PASS / 0 FAIL (+17 new tests over main)npm run build— cleantsc --noEmit -p tsconfig.server.json— cleanSELECT * FROM channels WHERE sourceId = '<mc-source>'reflects the device's channel list after connectNew tests
meshcoreNativeBackend.test.ts— get_channels mapping, set_channel validation (idx range, 16-byte secret), delete_channel pass-throughmeshcoreManager.channels.test.ts(new file) — listChannels, setChannel/deleteChannel re-sync, syncChannelsFromDevice shape + scoping + empty-secret handlingchannels.test.ts(repo) — new "preserves out-of-range channels owned by a MeshCore source" caseNot in this PR (phases 2 & 3)
MeshCoreChannelsView(still hardcoded to one "Public" channel)ChannelsConfigSection🤖 Generated with Claude Code