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
endWho 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).
Summary
Functions
Assigns an empty Phoenix.HTML.Form for a command under key. Pass params to prefill it.
Assigns the caller's Arc.Identity.Result (the same data GET /.cratis/me serves) under key.
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.
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.
Builds the Arc context for the current caller.
Executes a command through the full pipeline as the current caller.
The caller's Arc.Identity.Result.
Executes the command with params and updates the form under key.
Validates params against the command (authorization, declarative rules, validate/2)
without recording anything, and assigns the form with its errors under key.
Functions
@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.
@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.
@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.
@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.
@spec context(Phoenix.LiveView.Socket.t(), keyword()) :: Arc.Context.t()
Builds the Arc context for the current caller.
@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}.
@spec identity(Phoenix.LiveView.Socket.t()) :: Arc.Identity.Result.t()
The caller's Arc.Identity.Result.
@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.
@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.