# `Flezha.SDK.Control`
[🔗](https://github.com/flezha/flezha_elixir_sdk/blob/v0.1.0/lib/flezha/sdk/control.ex#L1)

Administering the namespace this runner's connection proved, from ordinary
application code. Sending to a relay is not here: it is
`Flezha.SDK.send/5`.

No tasklet has to be running and the application holds no credential of its
own: the controller judges every call as the identity the connection already
established, so nothing an unattended process holds expires. A user
grants a namespace's applications the authority once and revokes it the same
way, and a revocation takes effect on the next call:

    flz role bind runner@team-orders app team-orders

Every function here is one line over `call/3`, because the verb travels as
data on the wire, through `flz_core`'s one administration entry. Adding a verb
costs a function and nothing else.

# `runner`

```elixir
@type runner() :: Flezha.SDK.t() | pid() | atom()
```

A runner handle, or the server behind one.

# `bind_plugin`

```elixir
@spec bind_plugin(runner(), String.t(), String.t(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Bind the relay `relay_id` to the enabled plugin `name`, with the
optional `hooks:` and `channel:`.

# `call`

```elixir
@spec call(runner(), String.t(), [term()]) ::
  {:ok, term()} | {:error, Flezha.SDK.Error.t()}
```

Any published function, by name.

What succeeds follows from the role the namespace is bound to, never from a
list kept here. `args` are the call's arguments other than the namespace,
which the controller fills from the connection.

# `cell_state`

```elixir
@spec cell_state(runner(), String.t(), String.t() | nil) ::
  {:ok, term()} | {:error, term()}
```

A relay's live state, and the change sequence it was read at. `cell` is
`<tasklet>[/<cell_key>]`: a tasklet's Cells, or one of them; `nil` reads
every Cell of the relay.

# `disable_plugin`

```elixir
@spec disable_plugin(runner(), String.t()) :: {:ok, term()} | {:error, term()}
```

Disable the plugin `name`, stopping it wherever it runs.

# `enable_plugin`

```elixir
@spec enable_plugin(runner(), String.t(), String.t(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Enable the plugin `name` in this namespace, of the provider `provider` (for
example `"relay_websocket"`). Options: `opts:`, the provider's options;
`single: true` to run one copy in the whole cluster; and
`relay_id:` with `hooks:` to bind that relay in the same call.

# `list_plugins`

```elixir
@spec list_plugins(runner()) :: {:ok, term()} | {:error, term()}
```

The plugins enabled in this namespace: name, provider, single, bound relays.

# `list_relays`

```elixir
@spec list_relays(runner()) :: {:ok, term()} | {:error, term()}
```

The relays in this namespace across the cluster: `rows`, one row each, and
`unreachable`, the controllers that did not answer.

# `start_relay`

```elixir
@spec start_relay(runner(), String.t(), keyword()) ::
  {:ok, %{id: String.t(), outcome: :started | :already_running}}
  | {:error, term()}
```

Start a relay of `factory_id`, on the specification `flz relay start`
takes: `id:`, `init_values:` and `opts:`, each optional. Answers the
id it runs under, the generated one when no `id:` was given, and whether this
call started it or found a live instance already holding the id.

Without `id:` every call starts a new relay, so a start retried after a
lost answer starts a second one, and a second stream runs until it is stopped.
Pass `id:` when the start may be retried.

# `stop_relay`

```elixir
@spec stop_relay(runner(), String.t()) :: {:ok, term()} | {:error, term()}
```

Stop a relay, or the whole partition group it names.

# `unbind_plugin`

```elixir
@spec unbind_plugin(runner(), String.t(), String.t()) ::
  {:ok, term()} | {:error, term()}
```

Unbind the relay `relay_id` from the plugin `name`, which stays enabled.

---

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