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'sfield_accessmap to a conn or LiveView socket so it lands as a prop on the Svelte component under both:restand:livemodes.errors/1— translate anEcto.Changesetinto the%{field => [msg, ...]}shape consumed byuseForm(REST) anduseLiveForm(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.
Summary
Functions
Publish a JSON-Patch on the conventional topic for an entity
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.
Translate an Ecto.Changeset into the %{field => [msg, ...]}
shape both useForm (REST) and useLiveForm (LiveView)
consume.
Attach a field_access map to a Plug.Conn or LiveView socket.
Functions
Publish a JSON-Patch on the conventional topic for an entity
actor pair. Thin wrapper over
CaravelaSvelte.SSE.publish/2that derives the topic viaentity_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.
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.
@spec errors(Ecto.Changeset.t()) :: %{optional(atom()) => [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.
@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 beforeCaravelaSvelte.render/4:conn |> CaravelaSvelte.Caravela.put_field_access(field_access) |> CaravelaSvelte.render("BookIndex", %{books: books, field_access: field_access})In a LiveView (
:live), call duringmount/3orhandle_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>.