# `Arc.LiveView`
[🔗](https://github.com/Cratis/Arc.Elixir/blob/main/lib/arc/live_view.ex#L5)

The Arc commands and queries, called in-process from a LiveView.

LiveView does not use the HTTP contract or generated TypeScript: it calls the same pipelines
the HTTP host does, so authorization, validation and recording behave identically on both.

    defmodule MyAppWeb.AuthorsLive do
      use MyAppWeb, :live_view
      use Arc.LiveView, application: MyApp.Arc

      def mount(_params, _session, socket) do
        {:ok,
         socket
         |> assign_observable(:authors, MyApp.Authors.Listing.Authors, :live_authors)
         |> assign_form(:form, MyApp.Authors.Registration.RegisterAuthor)}
      end

      def handle_event("validate", %{"command" => params}, socket),
        do: {:noreply, validate_form(socket, :form, params)}

      def handle_event("save", %{"command" => params}, socket) do
        case submit_form(socket, :form, params) do
          {:ok, _result, socket} -> {:noreply, put_flash(socket, :info, "Registered")}
          {:error, socket} -> {:noreply, socket}
        end
      end
    end

## Who is the caller

The principal is read from the socket's assigns each time a command or query runs, not once
at mount, so a signed-out or demoted user is caught on the next call. By default Arc reads
`assigns.arc_principal`, then `assigns.current_scope.user`, then `assigns.current_user`. Pass
`principal: {Module, :function}` to `use Arc.LiveView` to resolve it your own way; the
function receives the socket and returns an `Arc.Principal`.

## Observable queries

`assign_observable/5` keeps an assign current. The subscription is a process that ends with the
LiveView, and the application must be started (`MyApp.Arc` in your supervision tree).

# `assign_form`

```elixir
@spec assign_form(Phoenix.LiveView.Socket.t(), atom(), module(), map()) ::
  Phoenix.LiveView.Socket.t()
```

Assigns an empty `Phoenix.HTML.Form` for a command under `key`. Pass `params` to prefill it.

# `assign_identity`

```elixir
@spec assign_identity(Phoenix.LiveView.Socket.t(), atom()) ::
  Phoenix.LiveView.Socket.t()
```

Assigns the caller's `Arc.Identity.Result` (the same data `GET /.cratis/me` serves) under `key`.

An anonymous caller gets a result with `authenticated?: false`. An application without an
identity provider gets empty details. Identity is presentation data, never an authorization
decision; commands and queries authorize themselves.

# `assign_observable`

```elixir
@spec assign_observable(
  Phoenix.LiveView.Socket.t(),
  atom(),
  module(),
  atom(),
  map(),
  keyword()
) ::
  Phoenix.LiveView.Socket.t()
```

Keeps `key` current: assigns the data now (so the connected render never flashes empty) and
again whenever the query's watched read models change or its topics are notified. Before the
socket connects, it is a one-shot read.

# `assign_query`

```elixir
@spec assign_query(
  Phoenix.LiveView.Socket.t(),
  atom(),
  module(),
  atom(),
  map(),
  keyword()
) ::
  Phoenix.LiveView.Socket.t()
```

Runs a query once and assigns its data to `key`, and the full `Arc.QueryResult` to
`:<key>_result`. A query that fails assigns an empty list or `nil`.

# `context`

```elixir
@spec context(Phoenix.LiveView.Socket.t(), keyword()) :: Arc.Context.t()
```

Builds the Arc context for the current caller.

# `execute`

```elixir
@spec execute(Phoenix.LiveView.Socket.t(), struct() | {module(), map()}, keyword()) ::
  {:ok, Arc.CommandResult.t()} | {:error, Arc.CommandResult.t()}
```

Executes a command through the full pipeline as the current caller.

Returns `{:ok, result}` when the command succeeded, otherwise `{:error, result}`.

# `identity`

```elixir
@spec identity(Phoenix.LiveView.Socket.t()) :: Arc.Identity.Result.t()
```

The caller's `Arc.Identity.Result`.

# `submit_form`

```elixir
@spec submit_form(Phoenix.LiveView.Socket.t(), atom(), map()) ::
  {:ok, Arc.CommandResult.t(), Phoenix.LiveView.Socket.t()}
  | {:error, Phoenix.LiveView.Socket.t()}
```

Executes the command with `params` and updates the form under `key`.

Returns `{:ok, result, socket}` on success, or `{:error, socket}` with the errors on the form.

# `validate_form`

```elixir
@spec validate_form(Phoenix.LiveView.Socket.t(), atom(), map()) ::
  Phoenix.LiveView.Socket.t()
```

Validates `params` against the command (authorization, declarative rules, `validate/2`)
without recording anything, and assigns the form with its errors under `key`.

---

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