# `CaravelaSvelte.Caravela`
[🔗](https://github.com/rsousacode/caravela_svelte/blob/v0.1.0/lib/caravela_svelte/caravela.ex#L1)

Integration surface for Caravela-generated apps.

The generators shipped by the `caravela` framework stitch
controllers, LiveViews, and Svelte components together. The
helpers in this module exist so generated code can do the
glue in one line instead of re-deriving it in every template:

  * `put_field_access/2` — attach the entity's `field_access`
    map to a conn or LiveView socket so it lands as a prop on
    the Svelte component under both `:rest` and `:live` modes.
  * `errors/1` — translate an `Ecto.Changeset` into the
    `%{field => [msg, ...]}` shape consumed by `useForm` (REST)
    and `useLiveForm` (LiveView).
  * `broadcast_patch/2` / `entity_topic/2` — publish a
    JSON-Patch on the conventional topic for a Caravela entity
    + actor pair, for SSE real-time pages.

Caravela's generators are expected to call these helpers at
well-known points; end-user code rarely touches the module
directly, though it's safe to.

`Ecto` and `Phoenix.LiveView` are optional dependencies. Their
clauses are compiled out when the module is missing.

# `broadcast_patch`

```elixir
@spec broadcast_patch(atom() | String.t(), term() | nil, list()) ::
  :ok | {:error, term()}
```

Publish a JSON-Patch on the conventional topic for an entity
+ actor pair. Thin wrapper over `CaravelaSvelte.SSE.publish/2`
that derives the topic via `entity_topic/2`.

    CaravelaSvelte.Caravela.broadcast_patch(:book, actor.id, [
      ["replace", "/title", "Updated"]
    ])

Pass `nil` as the actor to broadcast to every subscriber of
the entity — useful for admin dashboards.

# `entity_topic`

```elixir
@spec entity_topic(atom() | String.t(), term() | nil) :: String.t()
```

Build the conventional SSE topic string for an entity scoped
to an actor. Centralised so Caravela's generators and runtime
agree on the wire format.

    iex> CaravelaSvelte.Caravela.entity_topic("Book", 42)
    "caravela:book:actor:42"

    iex> CaravelaSvelte.Caravela.entity_topic(:book, nil)
    "caravela:book"

Entity names are normalised to lowercase. `nil` actors drop
the `:actor:<id>` suffix for broadcast-to-all patterns.

# `errors`

```elixir
@spec errors(Ecto.Changeset.t()) :: %{optional(atom()) =&gt; [String.t()]}
```

Translate an `Ecto.Changeset` into the `%{field => [msg, ...]}`
shape both `useForm` (REST) and `useLiveForm` (LiveView)
consume.

Merges the changeset's `:action` before traversal so templates
that haven't explicitly marked the changeset as validated still
surface errors. Interpolates `%{count}` placeholders from the
error `opts`.

Requires `Ecto` at runtime; raises otherwise.

# `put_field_access`

```elixir
@spec put_field_access(Plug.Conn.t(), map()) :: Plug.Conn.t()
@spec put_field_access(Phoenix.LiveView.Socket.t(), map()) ::
  Phoenix.LiveView.Socket.t()
```

Attach a `field_access` map to a Plug.Conn or LiveView socket.

Works uniformly in `:rest` and `:live` modes:

  * In a Phoenix controller (`:rest`), call before
    `CaravelaSvelte.render/4`:

        conn
        |> CaravelaSvelte.Caravela.put_field_access(field_access)
        |> CaravelaSvelte.render("BookIndex", %{books: books, field_access: field_access})

  * In a LiveView (`:live`), call during `mount/3` or
    `handle_params/3`:

        {:ok, CaravelaSvelte.Caravela.put_field_access(socket, field_access)}

The function just assigns `:field_access` so downstream code
can read `@field_access` in templates and pass it as a prop to
`<CaravelaSvelte.svelte>`.

---

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