lariv-rs 0.1.0

Compile-time plugin web application framework built on Axum, SeaORM, Maud, and HTMX
Documentation
//! Plugin entrypoint — `define_plugin_install!` and install steps.
//!
//! # Plugin definition (`mod.rs`)
//!
//! Every plugin lives in `src/plugins/<name>/mod.rs` (or `src/plugins/<name>.rs` for small
//! plugins). The file declares:
//!
//! 1. A **tag struct** (e.g. `HelloTag`) — identifies the plugin in the capability system.
//! 2. Submodule declarations (`routes`, `templates`, `handlers`, …).
//! 3. An **`install` function** generated by [`define_plugin_install!`](crate::plugin_install::define_plugin_install).
//!
//! ```ignore
//! pub mod routes;
//! pub mod templates;
//! pub mod handlers;
//!
//! pub struct MyPluginTag;
//!
//! define_plugin_install! {
//!     plugin: MyPluginTag;
//!     /// Doc comment attached to the generated `install` function.
//!     steps: [
//!         apps(apps::Hook),
//!         migrations(migrations::Hook),
//!         templates(templates::Hook),
//!         slots(templates::SlotsHook),
//!         config(MyConfigTag, MyConfig),
//!         http(routes::Hook),
//!         state(StateHook),
//!         seeds(SeedsHook),
//!         commands(cli::Hook),
//!     ]
//! }
//! ```
//!
//! # Install steps
//!
//! Each step prepends a deferred hook onto a core capability. At mount time hooks fold
//! in reverse install order (last plugin wins for conflicting registrations).
//!
//! | Step | Registers |
//! |------|-----------|
//! | `cap_attach($Tag, $Cap, $expr)` | Prepend a custom builder capability (tag must be absent) |
//! | `cap_hook($Tag, $Cap, $hook)` | Prepend a hook on an existing tagged capability |
//! | `apps($hook)` | Dashboard app tile |
//! | `migrations($hook)` | SeaORM migrator |
//! | `templates($hook)` | Maud page types |
//! | `slots($hook)` | Shell chrome slots (topbar, head, …) |
//! | `config($Tag, $Ty)` | TOML config section with defaults |
//! | `http($hook)` | HTTP routes |
//! | `state($hook)` | Runtime state after DB connect |
//! | `seeds($hook)` | Startup seed data |
//! | `commands($hook)` | CLI subcommands |
//! | `grapesjs($hook)` | Website builder blocks |
//! | `tools($hook)` | LLM function-calling tools |
//! | `export($hook)` | XLSX export catalog tables |
//! | `rune_env($hook)` | Rune script bindings |
//!
//! # Custom capabilities (`cap_attach` / `cap_hook`)
//!
//! Core Lariv capabilities (templates, apps, HTTP, …) are always present on a web app.
//! Deployments can add **local builder capabilities** — a struct in your crate that
//! implements [`Capability`](crate::capability::Capability) and [`HasCapTag`](crate::capability::HasCapTag),
//! with plugin hooks prepended via [`CapHookExt`](crate::capability::CapHookExt).
//!
//! Use `cap_attach` once (first plugin that owns the capability) to prepend the empty
//! builder to the stack. Later plugins — including addons in other crates — use
//! `cap_hook` to register their hook without re-attaching the capability:
//!
//! ```ignore
//! // Hub plugin (creates the capability + base hook)
//! define_plugin_install! {
//!     plugin: AccountsTag;
//!     steps: [
//!         cap_attach(SidebarTag, SidebarCap, SidebarCap::<frunk::HNil>::new()),
//!         cap_hook(SidebarTag, SidebarCap, sidebar::BaseHook),
//!         apps(apps::Hook),
//!         // ...
//!     ]
//! }
//!
//! // Addon plugin (patches the shared capability)
//! define_plugin_install! {
//!     plugin: CustomerTag;
//!     steps: [
//!         cap_hook(accounts::SidebarTag, accounts::SidebarCap, accounting_sidebar::Hook),
//!         apps(apps::Hook),
//!         // ...
//!     ]
//! }
//! ```
//!
//! At [`App::mount`](crate::app::App::mount), hooks fold over the capability's items in
//! reverse install order (tail first). `$Cap` is the type constructor (e.g. `SidebarCap`
//! for `SidebarCap<Hooks>`); `$expr` is typically `SidebarCap::<frunk::HNil>::new()`.
//!
//! See [`crate::plugin_install`] for the full step reference.
//!
//! Plugins that need shared runtime state (DB handle, config, caches) define a
//! [`StateHook`](crate::hooks::AttachState) and use `define_passthrough_cap!`:
//!
//! ```ignore
//! use lariv_rs::capability::{CapStore, define_passthrough_cap};
//!
//! pub struct MyState { /* fields */ }
//!
//! define_passthrough_cap!(MyStateCap, MyPluginTag, MyState);
//!
//! pub struct StateHook;
//!
//! impl AttachState<L, Proof> for StateHook {
//!     type Output = HCons<MyStateCap, L>;
//!     fn attach_state(app: App<L>) -> App<Self::Output> {
//!         // read DbTag + ConfigTag, construct MyState, add_capability(...)
//!     }
//! }
//! ```
//!
//! Simpler plugins (like dashboard) can attach state eagerly in the install macro:
//!
//! ```ignore
//! define_plugin_install! {
//!     plugin: DashboardTag;
//!     steps: [templates(templates::Hook), http(routes::Hook)];
//!     finish: add_capability(DashboardStateCap, CapStore::with_items(DashboardState));
//! }
//! ```
//!
//! # Dashboard app tile
//!
//! Visible plugins register a tile so operators can launch them from `/dashboard`:
//!
//! ```ignore
//! // apps.rs
//! define_register_apps! {
//!     plugin: MyPluginTag;
//!     key: "my_plugin";
//!     name: "My Plugin";
//!     href: "/my-plugin";
//!     icon: "sparkles";
//!     roles: ["admin"];
//! }
//! ```
//!
//! Add `apps(apps::Hook)` to the install steps and include `apps.rs` in the plugin module.