A heartbeat that goes quiet when the route is dead: signed presence records with a short TTL A developer of Bolo, an Android app that turns a phone into a microphone for a PC, published a 146-line Node.js presence module that signs short-lived lookup records with an EC (prime256v1) key, hashing the public key into the server ID and storing only a hash of the lookup token. Records expire after 150 seconds and are re-sent every 45 seconds, and a refresh now runs an injected route health check first so a dead tunnel URL goes silent and expires rather than leaving the phone showing a stale online status. The module switched to fetch with a 10-second AbortSignal timeout after a CI runner on a datacenter network received a bot challenge to a bare https.request while fetch from the same machine got a 200. Disclosure: I'm the developer of the app described here, and this post was drafted and published by an AI agent from the project's source code. Bolo https://play.google.com/store/apps/details?id=com.ashwar.bolo&referrer=utm source%3Ddevto%26utm medium%3Darticle search Bolo AI on Google Play turns an Android phone into a microphone for a computer. On the same Wi-Fi the phone finds the PC directly. Away from it, the PC's Node.js helper publishes a small "I'm here, reach me at this URL" record that the phone looks up. This post covers src/presence.js , the 146-line module behind that record, and four decisions in it. The helper generates an EC key pair prime256v1 once and keeps it in its settings file. The server ID is the SHA-256 of the public key, so identity is the key, not a name anyone can claim. Each record is signed over a canonical, newline-joined payload of fixed fields in a fixed order server ID, URL, display name, version, boot ID, reported-at, expires-at, lookup-token hash : record.signature = crypto.sign 'sha256', Buffer.from canonicalPresencePayload record , 'utf8' , identity.privateKey .toString 'base64' ; Signing a canonical string instead of JSON.stringify record matters: key order and whitespace in JSON are not guaranteed to survive a round trip, and a signature check that depends on them fails for no good reason. The phone looks the PC up by a random lookup token, but the record stores only its hash, so the lookup service holds nothing that lets it replay the lookup. Records expire after 150 s and the helper re-sends every 45 s: three chances to refresh before a record lapses. A PC that is switched off just stops sending and falls out of the lookup on its own, with no "goodbye" message to lose. The interval timer is unref ed so the heartbeat never keeps the process alive by itself. This is the fix that taught me the most. A record for a tunnel URL that no longer reached the PC made the phone show the PC as online, and then every tap failed. The refresh now asks a health check first: async function publishPresence { if currentTunnelUrl || currentVersion return false; if routeHealthy return false; ... } routeHealthy is injected setRouteHealthCheck and defaults to "yes", which keeps the module testable. When the probe says the URL does not reach this machine, the helper stays silent, the old record expires within the TTL, and the phone sees "offline", which is true. Absence of a record is more honest than a stale one. A rejected refresh now logs who rejected it. The service answers with JSON; an edge bot-challenge answers with HTML. So the log line is either proxy: {...} or edge cf-mitigated=..., ray=... . On one CI runner on a datacenter network, the edge had answered a bare https.request with a bot challenge while fetch from the same machine got a 200. Home networks passed both. The module now uses fetch with a 10 s AbortSignal.timeout , and the log makes the next such difference diagnosable in one line instead of a guessing game. Bolo is on Google Play search Bolo AI : https://play.google.com/store/apps/details?id=com.ashwar.bolo https://play.google.com/store/apps/details?id=com.ashwar.bolo . The presence record carries only a server ID, a URL, a display name and version info, signed by the PC's own key; it does not carry dictated text.