# `NervesGate.Remote`

Tailscale connection and device-name control.

## Commands

`connect/3`, `configure/3` and `disconnect/1` return `:ok` when accepted,
or `{:error, reason}`. Only one daemon operation runs at a time. Acceptance
does not mean completion: read `status/1` for `:operation` and `:error`.
Editors pass `expected:`, the hostname their draft started from; a changed
hostname is rejected as stale before any daemon write.

## Queries and notifications

`status/1` returns sanitized daemon observations. `login_url/1` is a private
query; its result never enters status or notifications. Subscribe with
`observe/1` before reading, then reread when properties change.

The optional server argument defaults to this module. The daemon retains
identity and preferences across process restarts; user commands are not replayed.
Once online with a DNS name, an owned worker configures HTTPS Serve on port 443
to the gateway UI on port 4000. It runs once per observed DNS name, including
startup and rename. A failed setup is not automatically retried; connect or save
the same device name to retry. The daemon persists the listener configuration.

`:remote_unavailable` reports daemon loss after a connect request or an active
authentication/connection observation. An available daemon clears it, including
while offline or awaiting approval. Stopped/unconfigured connections do not
require a daemon for this alarm. Unknown startup observations preserve an old
report; no connection intent is persisted here.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `configure`

```elixir
@spec configure(String.t(), GenServer.server(), keyword()) :: :ok | {:error, term()}
```

Request a hostname change without changing connection intent; preserves omitted preferences.

# `connect`

```elixir
@spec connect(String.t(), GenServer.server(), keyword()) :: :ok | {:error, term()}
```

Request connection or enrollment. Optional `auth_key:` is transient, never persisted.

# `disconnect`

```elixir
@spec disconnect(GenServer.server()) :: :ok | {:error, term()}
```

Request Tailscale down without logging out. May disconnect a caller using the VPN.

# `login_url`

```elixir
@spec login_url(GenServer.server()) :: String.t() | nil
```

Read the validated HTTPS enrollment URL, or nil. Do not log or broadcast it.

# `observe`

```elixir
@spec observe(GenServer.server()) :: :ok | {:error, :unavailable}
```

Subscribe the caller to property-change hints; read status afterward and on each notification.

# `status`

```elixir
@spec status(GenServer.server()) :: map()
```

Read daemon observations and the current operation/error. Never returns an enrollment URL.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
