fix: hide web mic button in non-secure contexts + tailscale recipe#31
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
v0.10.0 ships voice support, but
navigator.mediaDevicesis undefined in non-secure contexts (anything other than HTTPS orhttp://localhost). On a defaultSOLRAC_WEB_HOST=0.0.0.0deploy, opening the UI via a LAN IP / Tailscale 100.x address over HTTP shows the mic button, then throwsCannot read properties of undefined (reading 'getUserMedia')on click.Two fixes:
Client feature-detect. Split the single
voiceFeatureAvailableflag into two: server-side voice availability (controls speak buttons + voice badge — both work over plain HTTP) andmicCaptureAvailable(server voice AND browser exposes the mic API). Mic button hides itself when the browser can't capture; one-time toast explains. Speak buttons keep working in non-secure contexts since<audio>doesn't need them.Doc the operational fix. Tailscale
serveis the cleanest single-tenant path to a real cert. Recipe lives indocs/SETUP.md §13(first-time setup),docs/USAGE.md §Web UI(general access from other devices),docs/USAGE.md §Voice surface(mic-specific), anddocs/RUNBOOK.md(diagnosis flow).Files
public/app.js—hasMicCaptureSupport()helper;micCaptureAvailableflag; one-shot toast;onMicClickgated on the new flag.docs/USAGE.md— secure-context note in Voice surface + new "Reaching the UI from other devices" subsection.docs/SETUP.md— Tailscale serve recipe in the web UI enablement step (replaces the vague "consider Tailscale" line).docs/RUNBOOK.md— new "Web UI mic button hidden /getUserMediaundefined" section with diagnosis + three recovery paths.Anti-goal status
None reversed. Tailscale is one of three documented options (localhost / Tailscale / reverse proxy with TLS) — recommended for single-tenant, not required.
Test plan
http://<lan-ip>:7134/) — mic hidden, toast fires, no console exception, speak buttons workrefreshVoiceState)http://localhost:7134/) — mic visible, no toast, STT round-trip writesvoice_eventsrow/api/ttscall)/voice off→ badge disappears)https://<host>.<tailnet>.ts.net/shows real Let's Encrypt cert, mic works from another device on the tailnet