When relay mode is used
Relay mode is triggered when WebRTC ICE negotiation fails to produce a usable direct or STUN-assisted candidate pair. This typically happens when:- Both sender and receiver are on enterprise or mobile networks with symmetric NAT
- A firewall blocks all UDP traffic and TURN-over-TCP is also unavailable
- The TURN server credentials are missing or expired
POST request. The receiver downloads and claims it via a GET request. The signaling server’s Warp Code is reused as the relay key.
How relay mode works
- The sender’s client detects that a direct WebRTC connection cannot be established.
- The sender
POSTs the file(s) to/api/relay/[code], tagged with the Warp Code. - The server stores the file in the OS temporary directory with a 15-minute expiry.
- The receiver enters the same Warp Code. The client
GETs/api/relay/[code], which returns the file and marks the entry as claimed. - Once claimed, the relay entry is immediately deleted from disk.
Data structures
The relay store (src/app/api/relay/store.ts) uses two TypeScript interfaces to represent a stored transfer:
RelayEntry.claimed is set to true the moment the receiver successfully downloads the file. Any subsequent request for the same code returns a 404. expiresAt is set to Date.now() + TTL_MS at upload time.
TTL and cleanup
sweepRelayEntries) scans the relay directory and deletes any entry whose expiresAt timestamp has passed. Entries that cannot be parsed are also removed during sweeps.
The relay store writes files to the OS temporary directory:
path.join(os.tmpdir(), 'hashdrop-relay-store'). On Linux this is typically /tmp/hashdrop-relay-store. Files in this location are not persisted across server restarts and may be cleared by the OS independently of HashDrop’s TTL sweep.API endpoints
| Method | Path | Description |
|---|---|---|
POST | /api/relay/[code] | Upload one or more files for the given Warp Code. Sets expiresAt and claimed: false. |
GET | /api/relay/[code] | Download the file(s) and atomically mark the entry as claimed. Deletes the entry after delivery. |
DELETE | /api/relay/[code] | Explicitly remove a relay entry before it expires (e.g., sender cancels). |