filedrop-mesh epic
This is a sub-issue of the umbrella epic: #155.
Description
The current QR encodes a single LAN URL: http://192.168.x.x:port/<token>#<key>. With mesh, a single QR needs to carry both the LAN URL and the mesh room code, because the receiver's phone doesn't know in advance which path will work.
This sub-issue defines and implements the QR + URL format that handles both cases transparently.
Goals
- One QR works in both same-network and cross-network scenarios.
- A phone scanning the QR never has to choose which transport to use — the receiver page figures it out.
- Backward-compatible: an old receiver client scanning a new QR can still hit the LAN URL if it's reachable.
Proposed URL format
The QR encodes a deep link on the signaling host:
https://<signal-host>/r/<ROOM>#<LAN_URL>?<key>
Where:
When the receiver opens the deep link, the receiver page:
- Reads
key from the fragment.
- Reads
LAN_URL from the fragment.
- Tries
LAN_URL first (cheap, fast, no signaling roundtrip).
- If the LAN URL is unreachable (timeout, connection refused), falls back to the signaling room
<ROOM> and switches to MeshTransport.
Why fragment for both LAN URL and key?
The fragment is never sent to the server. Both the LAN URL and the key ride in the fragment so neither leaks through any HTTP request — including the initial GET to the signaling host's landing page. The signaling host only ever sees the room code in the path.
Fallback for old clients
For receivers running an older filedrop web client that doesn't understand the new format, the QR can also embed the plain LAN URL as a fallback path (e.g., via a tiny JavaScript shim that detects old clients and redirects). Decide the exact mechanism in the PR; the simplest is to encode both URLs in the fragment separated by a sentinel character.
Expected vs Actual
Expected: One QR. Two transport paths. The receiver picks the working one.
Actual: One QR. One path. LAN-only.
Steps to land
- Define the URL schema above in
docs/mesh-url-format.md (small spec doc).
- Sender: build the QR string in
src/qr.js from (signalUrl, roomCode, lanUrl, keyHex).
- Receiver: update the landing page to parse the new format, try the LAN URL with a short timeout, fall back to mesh.
- Backward compatibility: detect an old client (User-Agent or version marker) and redirect to the LAN URL only.
- Terminal UI: show the mesh code alongside the LAN URL in the metadata box, with a clear visual indicator that mesh is active.
- Tests:
- QR string roundtrips through the parser.
- LAN-URL-first-then-mesh fallback: unit-test the decision logic with mocked timeouts.
- Old-client detection redirects correctly.
Location
- modified:
src/qr.js — renderMeshQR(signalUrl, roomCode, lanUrl, keyHex, options)
- modified: the receiver-side HTML served at the LAN URL — add the format-detection + fallback logic
- new doc:
docs/mesh-url-format.md
Difficulty
Medium — the format itself is simple; the receiver-side fallback timer and old-client detection need real device testing.
Dependencies
Notes
Pick a sentinel character for the fragment that won't appear in URL-encoded payloads. Newline is safe since fragments are URL-encoded by the browser before the page reads them. Document the choice in the spec doc.
Part of the filedrop-mesh epic (#155).
filedrop-mesh epic
This is a sub-issue of the umbrella epic: #155.
Description
The current QR encodes a single LAN URL:
http://192.168.x.x:port/<token>#<key>. With mesh, a single QR needs to carry both the LAN URL and the mesh room code, because the receiver's phone doesn't know in advance which path will work.This sub-issue defines and implements the QR + URL format that handles both cases transparently.
Goals
Proposed URL format
The QR encodes a deep link on the signaling host:
Where:
<signal-host>— the configured signaling server (sub-issue test: CI Auto-Fix Loop with Greptile and Jules #3).<ROOM>— the 6-char mesh room code (sub-issue test: Jules-Greptile V2 Loop Test #4).<LAN_URL>— the local URL the sender is currently bound to. URL-encoded. Optional — omit if the sender has no LAN address.<key>— the AES key fragment, in the URL fragment so it never goes over the network in plaintext.When the receiver opens the deep link, the receiver page:
keyfrom the fragment.LAN_URLfrom the fragment.LAN_URLfirst (cheap, fast, no signaling roundtrip).<ROOM>and switches to MeshTransport.Why fragment for both LAN URL and key?
The fragment is never sent to the server. Both the LAN URL and the key ride in the fragment so neither leaks through any HTTP request — including the initial GET to the signaling host's landing page. The signaling host only ever sees the room code in the path.
Fallback for old clients
For receivers running an older
filedropweb client that doesn't understand the new format, the QR can also embed the plain LAN URL as a fallback path (e.g., via a tiny JavaScript shim that detects old clients and redirects). Decide the exact mechanism in the PR; the simplest is to encode both URLs in the fragment separated by a sentinel character.Expected vs Actual
Expected: One QR. Two transport paths. The receiver picks the working one.
Actual: One QR. One path. LAN-only.
Steps to land
docs/mesh-url-format.md(small spec doc).src/qr.jsfrom(signalUrl, roomCode, lanUrl, keyHex).Location
src/qr.js—renderMeshQR(signalUrl, roomCode, lanUrl, keyHex, options)docs/mesh-url-format.mdDifficulty
Medium — the format itself is simple; the receiver-side fallback timer and old-client detection need real device testing.
Dependencies
Notes
Pick a sentinel character for the fragment that won't appear in URL-encoded payloads. Newline is safe since fragments are URL-encoded by the browser before the page reads them. Document the choice in the spec doc.
Part of the filedrop-mesh epic (#155).