# `Issho.Engine`
[🔗](https://github.com/hattoriai/issho/blob/v0.4.0/lib/issho/engine.ex#L1)

The model of a document: how its operations apply. Each binding brings
one (Kotoba's text, Hakushi's graph, a map for shared assigns), and the
authority (`Issho.Authority`) runs it.

An engine is pure: no I/O, no clock, no randomness. The same operations
on the same state give the same state on every node, in a test, and in
the browser's twin of the engine. That is also what lets an engine move
to a NIF or to WebAssembly unchanged.

Its state is a map of strings, numbers, booleans, `nil`, lists and maps
with string keys (JSON) when browsers hold the document (they receive
it, and run the engine's twin) or the store saves JSON. A document only
LiveViews and agents hold, kept by no store or a store of terms, can be
any Erlang term: a struct of your own.

Everything outside the engine treats operations as opaque: the authority,
the store, receipts, the journal and the offline queue see only a
transaction's id, its base revision and its author.

## Callbacks

  * `c:name/0` and `c:version/0` tag every stored state, so that a
    document can move to another engine, or a new version, on its own
    schedule.
  * `c:init/2` builds a state from the initial content your policy gives
    (`c:Issho.Policy.document/2`).
  * `c:apply/3` applies one transaction's operations, all or none.
  * `c:validate/2` checks a state and gives its content: what your app
    publishes and the store keeps beside the state (a rendered HTML, a
    graph). Without it, the content is the state.
  * `c:snapshot/1` is what a browser receives when it opens the
    document. Without it, the state.
  * `c:upgrade/1` takes a stored document of another version of the
    engine, or one saved before Issho in a library's own format, and
    gives its `"state"`, `"epoch"` and `"revision"`, and its
    `"receipts"` if it kept them. With an `"initial"` state and a
    `"journal"` of the transactions since, earlier revisions can be
    rebuilt. Keep the epoch and revision the store has, so that the
    first save after the upgrade finds the version it expects.
    The upgraded document is saved with the next transaction; until
    then the store keeps it as it was. Without it, such a document does
    not open.

# `operation`

```elixir
@type operation() :: map()
```

# `state`

```elixir
@type state() :: map()
```

# `apply`

```elixir
@callback apply(state(), [operation()], opts :: keyword()) ::
  {:ok, state()} | {:error, term()}
```

The state after a transaction's operations, all or none. `opts` has the
engine's options and `:author`, the key of the actor who made it.

# `init`

```elixir
@callback init(initial :: term(), opts :: keyword()) :: {:ok, state()} | {:error, term()}
```

A state from the initial content of a document.

# `name`

```elixir
@callback name() :: String.t()
```

The engine's name, stored with every state: `"map"`, `"kotoba"`.

# `snapshot`
*optional* 

```elixir
@callback snapshot(state()) :: map()
```

The state a browser receives when it opens the document.

# `upgrade`
*optional* 

```elixir
@callback upgrade(stored :: map()) :: {:ok, map()} | {:error, term()}
```

A stored document of another version, or format, as this engine's.

# `validate`
*optional* 

```elixir
@callback validate(state(), opts :: keyword()) :: {:ok, term()} | {:error, term()}
```

Checks a state and gives its content.

# `version`

```elixir
@callback version() :: pos_integer()
```

The version of the engine's state and operations.

---

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