Gateway pairing helpers for remote clients.
The QR payload is deliberately tiny and URL-shaped so native apps can scan it without an HTTP round trip:
vis://gateway?url=http%3A%2F%2F100.64.0.10%3A7890&token=...
Tailscale fits naturally: if a 100.64.0.0/10 interface is present we prefer it over LAN addresses, otherwise we fall back to site-local IPv4 addresses.
Gateway pairing helpers for remote clients. The QR payload is deliberately tiny and URL-shaped so native apps can scan it without an HTTP round trip: vis://gateway?url=http%3A%2F%2F100.64.0.10%3A7890&token=... Tailscale fits naturally: if a 100.64.0.0/10 interface is present we prefer it over LAN addresses, otherwise we fall back to site-local IPv4 addresses.
(candidate-hosts bind-host)Reachable hostnames/IPs worth showing in a pairing QR, in preference order. Tailscale addresses come first because they keep working off-LAN; then LAN; then the server's bind host when concrete.
Reachable hostnames/IPs worth showing in a pairing QR, in preference order. Tailscale addresses come first because they keep working off-LAN; then LAN; then the server's bind host when concrete.
(pairing-url {:keys [host port token]})The vis://gateway deep link. url= is the best guess (Tailscale first), and
alt= carries the remaining routable hosts so a phone that cannot reach the
first one (no Tailscale, different LAN) falls back instead of failing. IPv4
link-local (169.254/16) is dropped from the alternates: no phone can route it,
and every extra host makes the QR denser.
The `vis://gateway` deep link. `url=` is the best guess (Tailscale first), and `alt=` carries the remaining routable hosts so a phone that cannot reach the first one (no Tailscale, different LAN) falls back instead of failing. IPv4 link-local (169.254/16) is dropped from the alternates: no phone can route it, and every extra host makes the QR denser.
(print-pairing! {:keys [require-token? emit] :or {emit println} :as opts})Emit the companion pairing block (title, reachable hosts, vis:// URL, and a
terminal QR). Each line goes through emit (default println); CLI callers
whose stdout is redirected to the log file pass a real-terminal writer so the
QR is actually visible. Returns the pairing URL payload.
Emit the companion pairing block (title, reachable hosts, `vis://` URL, and a terminal QR). Each line goes through `emit` (default `println`); CLI callers whose stdout is redirected to the log file pass a real-terminal writer so the QR is actually visible. Returns the pairing URL payload.
(tailscale-hosts)Tailscale (100.64/10) IPv4 addresses currently bound to a live interface, in
discovery order. Empty when Tailscale is not up, so callers can fall back to
LAN / 0.0.0.0 guidance.
Tailscale (100.64/10) IPv4 addresses currently bound to a live interface, in discovery order. Empty when Tailscale is not up, so callers can fall back to LAN / `0.0.0.0` guidance.
(terminal-qr text)Render text as a terminal QR code using Unicode half-blocks. Returns a string
so tests and CLI callers can decide where to print it.
Two properties matter for a phone camera to actually decode this:
qrencode -t UTF8, so the
code reads correctly on the dark terminal themes everyone runs. Painting
dark modules instead produces a photo-negative that most scanners reject.Render `text` as a terminal QR code using Unicode half-blocks. Returns a string so tests and CLI callers can decide where to print it. Two properties matter for a phone camera to actually decode this: - a full 4-module quiet zone (the spec minimum; a 1-module margin scans only on a perfect white background), padded to an even module height so the bottom quiet zone survives the half-block row packing; - the block glyph paints the *light* modules, like `qrencode -t UTF8`, so the code reads correctly on the dark terminal themes everyone runs. Painting dark modules instead produces a photo-negative that most scanners reject.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |