What a component in a mishka.ui_kit.bundle.v3 file has to look like before this CMS will install
it.
A bundle is a THIRD PARTY's JSON — Chelekom's today, a headless kit's or somebody's own tomorrow —
and until this module the only check was that components was a list. Everything past that was
trusted, so a component missing its template, or shipping attrs as an object instead of an array,
travelled all the way into Ash.create! and raised there. From the installer that is a failed
install; from the Studio's Install button it took the editor's LiveView down with it.
The contract is deliberately about SHAPE, not content: names, types, and which fields have to be
present for the rest of the pipeline (UiKitCatalog, Inspector, PaletteEntry, the runtime
compiler) to mean anything. A kit is free to add fields this CMS has never heard of —
UiKitHandler drops those at the Ash boundary — and free to leave optional ones out.
What happens to a component that fails
It is skipped and named, exactly as an unreadable bundle file already is. One malformed component in a kit of 136 should cost that component, not the kit.
Summary
Functions
Checks one component from a bundle.
A sample %MishkaCmsCore.UiKit.Contract{} populated from defaults + type-based fallbacks.
The fields the contract governs, for anyone documenting or testing the boundary.
Splits a bundle's components into the ones this CMS can install and the ones it cannot.
Types
@type t() :: %MishkaCmsCore.UiKit.Contract{ attrs: list() | nil, dependencies: list() | nil, extra: map() | nil, helpers: list() | nil, name: String.t() | nil, precompile: boolean() | nil, required: boolean() | nil, slots: list() | nil, stateful: boolean() | nil, template: String.t() | nil, type: String.t() | nil }
Functions
Checks one component from a bundle.
Returns the reason as a short atom-or-tuple rather than GuardedStruct's own error shape, because the caller writes it into an installer log line, not a form.
A sample %MishkaCmsCore.UiKit.Contract{} populated from defaults + type-based fallbacks.
@spec fields() :: [atom()]
The fields the contract governs, for anyone documenting or testing the boundary.
Splits a bundle's components into the ones this CMS can install and the ones it cannot.
Returns {kept, rejected} where rejected is [{name_or_nil, reason}] — enough for the caller to
say which components were skipped and why.