# `Issho.Live`
[🔗](https://github.com/hattoriai/issho/blob/v0.2.0/lib/issho/live.ex#L2)

A LiveView in a room: the same session as a browser's channel or an
agent's process, in the LiveView's own process. Presence, awareness,
the room's documents and the policy work the same; the room's events
reach the LiveView's components with `send_update/2`, or the LiveView
itself.

    live_session :default, on_mount: [Issho.Live] do

    # In a LiveView or one of its components, once connected:
    {:ok, _session} = Issho.Live.join(MyApp.Issho, current_user, "board:42")
    {:ok, snapshot} = Issho.Live.open("board:42", "board:42", notify: {MyComponent, "board"})

A component named in `notify` gets `update/2` with an `:issho` assign
for each event, `{event, key, payload}`:

  * `{"tx", document_id, accepted_transaction}`: a transaction accepted
    in a document it opened;
  * `{"aware", room, frame}`: the others' awareness;
  * `{"presence_diff", room, diff}`: people who came and went;
  * `{"bye", room, reason}`: the session ended (revoked, refused).

`notify: :self` sends them to the LiveView as
`{Issho.Live, event, key, payload}` messages instead.

## Grants: rooms the browser joins

A component whose browser half joins the room itself (a text editor,
which applies its own changes in the browser) needs a grant: a short
token for the room, signed by the LiveView for the actor it
authenticated. `grant/4` signs it and remembers it, and the hook
renews it when the browser asks (the `"issho:grant"` event, with the
room), after asking the policy again, so that a person whose access
went away gets no new grant. One grant serves every component of the
page in that room.

    grant = Issho.Live.grant(MyApp.Issho, current_user, "notebook:7", can: :write)

The components of a LiveView share one session per room: joining a
room the LiveView is in already gives the same session.

Join only in a connected LiveView (`connected?(socket)`): the static
render has no process that lasts.

# `target`

```elixir
@type target() :: {module(), term()} | :self
```

# `aware`

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

Sets this session's awareness state (`nil` clears it).

# `awareness`

```elixir
@spec awareness(String.t()) :: map()
```

This session's own awareness state (an empty map for none).

# `grant`

```elixir
@spec grant(atom(), Issho.Actor.t(), String.t(), keyword()) :: map()
```

A grant for the browser to join the room as the actor: `%{"room",
"token", "can", "self", "socket", "max_channels"}`, for a component's
browser half. The LiveView renews it when the browser asks. Options:
`:can` (`:write` or `:read`), `:claims`, `:on_behalf_of`, `:socket`
(the Issho socket's path, `"/issho/socket"`) and `:max_channels`
(that socket's `:max_channels_per_transport`, 100).

# `join`

```elixir
@spec join(atom(), Issho.Actor.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Joins a room as an actor, from this LiveView, or gives the session the
LiveView already has there. Options: `:can` (`:write`), `:claims`,
`:on_behalf_of`.

# `merge`

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

Merges keys into this session's awareness state: for the components of
a LiveView that share its session in a room, each setting its own
keys (a grid its place, another component its own key).

# `open`

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

Opens a document of the room. Options: `:notify`, a component
(`{module, id}`) or `:self`, for its transactions and the room's events;
and `:spec`, what the document is if this opens it first (see
`Issho.Documents.open/4`).

# `people`

```elixir
@spec people(String.t()) :: map()
```

The people of the room now: `Phoenix.Presence`'s list, by actor key.

# `read`

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

The document's current snapshot, from its authority.

# `session_id`

```elixir
@spec session_id(String.t()) :: String.t() | nil
```

The session id of this LiveView in the room, or `nil`.

# `states`

```elixir
@spec states(String.t()) :: map()
```

The awareness states of the room's sessions, from every node:
`%{session_id => %{"key" => actor_key, "state" => state}}`, for a
component that draws the others itself.

# `subscribe`

```elixir
@spec subscribe(String.t(), target()) :: true
```

Sends the room's events to a component, or the LiveView, without opening a document.

# `transact`

```elixir
@spec transact(String.t(), String.t(), [term()] | map()) ::
  {:ok, map()} | {:error, term()}
```

Commits to an open document: a list of operations (on the document's
latest revision) or a whole transaction.

---

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