Feat/pairing qr redesign - #42
Conversation
…ring Pairing failed in practice: a 90s rendezvous timeout closed the room before a human could carry a 12-word code to a second device; manual transcription was error-prone (a slip onto a different-but-valid word silently diverged the topic); and there was no TURN fallback for cross-network NAT. - Remove the hard 90s timeout — the room stays open until cancel, with a soft "still waiting/searching" hint after 30s. - Wire the previously-decorative TURN preference end-to-end (lib/trystero/ice.ts -> joinTopic -> joinRoom). Ships STUN-only: no reliable free public TURN exists (Open Relay verified dead 2026-06-01), so the server list is empty and enabling cross-network is a one-constant edit in ice.ts. - studyvis://pair?c=... pairing link (pairLink.ts): host copies the link, a paste fills all 12 slots, and the QR encodes the same link. BIP39 checksum gate on Connect catches transcription typos before submit. - Scan QR via webcam (PairQrScanner + jsqr) to auto-fill and connect; camera-denied falls back to paste. Shared lib/media.ts stream helper. Deps: qrcode, jsqr, @types/qrcode. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump app version 1.0.4 -> 1.1.0 (package.json, tauri.conf.json, Cargo.toml, Cargo.lock) for the pairing redesign. The release workflow now marks tags containing a prerelease suffix (e.g. v1.1.0-rc.1) as GitHub prereleases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Friend discovery (pairing, inbox, presence) rendezvous over trystero's default Nostr strategy, but joinTopic never passed relayConfig. So trystero fell back to its appId-seeded shuffle: every StudyVis peer deterministically lands on the SAME 5 relays from the bundled ~56-relay pool. Overlap is 100% by construction, but those 5 may be low-uptime or unreachable from a given network, with no diversity or fallback — discovery then fails symmetrically for everyone, with no recovery. Pin relayConfig.urls (src/lib/trystero/relays.ts) to 8 relays verified live on 2026-06-01 via an ephemeral-event publish/subscribe round-trip — the exact mechanism trystero rendezvous depends on. Passing urls makes trystero use the whole list, replacing "whichever 5 the hash picked" with a vetted, more redundant set. relay.damus.io and relay.froth.zone were unreachable at verification time and are deliberately omitted. Also: thread an optional relayConfig override through TopicConfig; warn instead of silently dropping the 'always' (relay-only) TURN preference when no TURN servers are configured; and correct ARCHITECTURE.md §4 — relay selection is deterministic per appId (not random), and the app ships STUN-only with no automatic TURN fallback (PUBLIC_TURN_SERVERS is empty). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (26)
📝 WalkthroughWalkthroughThis PR enhances the peer pairing feature with QR code generation and scanning, introduces a curated relay and TURN configuration system, refactors timeout behavior to user-friendly long-wait hints, and updates the pairing dialog UI to support both QR codes and encoded pairing links alongside traditional word entry. ChangesQR-Code Pairing Workflow
Sequence Diagram(s)sequenceDiagram
participant User
participant HostPanel
participant PairQrCode
participant JoinPanel
participant PairQrScanner
participant pair.ts
User->>HostPanel: open pairing dialog
HostPanel->>PairQrCode: render QR for words
PairQrCode-->>User: show QR code image
User->>HostPanel: click copy link
HostPanel-->>User: clipboard has pairing URL
User->>JoinPanel: paste or scan
alt Paste flow
User->>JoinPanel: paste link
JoinPanel->>JoinPanel: decodePairLink
JoinPanel->>JoinPanel: validate checksum
JoinPanel-->>User: enable connect if valid
else Scan flow
User->>JoinPanel: click scan
JoinPanel->>PairQrScanner: start camera
PairQrScanner-->>User: show video stream
User->>PairQrScanner: point at QR
PairQrScanner->>JoinPanel: onDecode(text)
JoinPanel->>JoinPanel: decodePairLink + validate
JoinPanel-->>User: auto-connect if valid
end
User->>JoinPanel: click connect
JoinPanel->>pair.ts: join with turnPreference
pair.ts->>pair.ts: buildIceOptions
pair.ts-->>User: peer connection established
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR redesigns the friend-pairing UX to support QR/link-based pairing (in addition to words), improves pairing correctness via BIP39 checksum validation, and hardens Trystero rendezvous configuration (relay pinning + optional ICE/TURN wiring). It also updates docs/tests and bumps the app version to 1.1.0.
Changes:
- Add pairing links (
studyvis://pair?c=...) with QR rendering + QR scanning + clipboard paste flow, and update pairing dialog copy/states (remove hard timeout; add “still waiting/searching” hint). - Add checksum validation for pairing codes to prevent “valid words but wrong room” silent failures.
- Pin curated Nostr relay URLs for rendezvous and add ICE/TURN option plumbing + tests; update release prerelease tagging logic and version numbers.
Reviewed changes
Copilot reviewed 26 out of 28 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/wordlist.test.ts | Adds tests for pairing-code checksum validation. |
| tests/unit/trystero-wrapper.test.ts | Extends Trystero wrapper tests to assert forwarded ICE + relay configuration. |
| tests/unit/relays.test.ts | Adds tests validating relay URL shape (wss, non-empty, no duplicates). |
| tests/unit/pairLink.test.ts | Adds tests for pairing link encode/decode behavior and invalid inputs. |
| tests/unit/media.test.ts | Adds tests for MediaStream stop helper behavior. |
| tests/unit/ice.test.ts | Adds tests for TURN preference → ICE option mapping and warnings. |
| src/strings.ts | Updates pairing dialog strings for QR/link UX, checksum hint, scan/paste flows, and long-wait hints. |
| src/stories/AddFriendDialog.stories.tsx | Updates Storybook stories for new phases/props and long-wait states. |
| src/lib/trystero/relays.ts | Introduces pinned curated DEFAULT_RELAY_URLS for Nostr rendezvous. |
| src/lib/trystero/index.ts | Adds optional ICE + relayConfig to TopicConfig and pins DEFAULT_RELAY_URLS by default. |
| src/lib/trystero/ice.ts | Adds TURN preference mapping + shipped server list stub (empty) and helpers. |
| src/lib/media.ts | Adds shared webcam-open and MediaStream stop utilities. |
| src/features/friends/wordlist.ts | Adds checksum validation helper using validateMnemonic. |
| src/features/friends/PairWordInput.tsx | Allows pasting a full pairing link to populate all word slots. |
| src/features/friends/pairLink.ts | Adds encode/decode for compact pairing links. |
| src/features/friends/pair.ts | Wires TURN preference into pairing (via buildIceOptions). |
| src/features/friends/index.ts | Re-exports new pairing helpers (checksum + pairLink). |
| src/features/friends/AddFriendDialogView.tsx | Adds QR code display, QR scan UI, paste button, checksum gating, and long-wait hints. |
| src/features/friends/AddFriendDialog.tsx | Removes deadline-based pairing timeout; adds long-wait hint timer; copies pairing link to clipboard; forwards TURN preference from settings. |
| src/components/PairQrScanner.tsx | Adds camera-based QR scanning component (jsQR). |
| src/components/PairQrCode.tsx | Adds QR rendering component (qrcode). |
| src-tauri/tauri.conf.json | Bumps app version to 1.1.0. |
| src-tauri/Cargo.toml | Bumps Rust package version to 1.1.0. |
| src-tauri/Cargo.lock | Updates locked version to 1.1.0. |
| package.json | Bumps version to 1.1.0 and adds jsqr, qrcode, @types/qrcode. |
| package-lock.json | Locks new dependencies and updated tree. |
| ARCHITECTURE.md | Updates Trystero strategy/relay selection and TURN documentation to match new wiring. |
| .github/workflows/release.yml | Makes prerelease status conditional on tag suffix (e.g. -rc.1). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (result?.data) { | ||
| stopped = true | ||
| onDecodeRef.current(result.data) | ||
| return | ||
| } |
Summary by CodeRabbit
New Features
Chores