frame-host 0.2.1

Frame host server and embedding seam — boots an application's frame-core component tree with an embedded liminal bus, announces the host's real application events on the bus, and serves the built frame page
Documentation
//! The embedding seam's application contract (design §4.2): everything an
//! embedding application supplies; frame-host supplies nothing.
//!
//! An [`AppSpec`] carries the application's component installs, its stated
//! runtime policy (no field has a default — frame supplies no lifecycle
//! defaults), a post-start readiness proof, and the application's fact
//! announcements. [`crate::application::run_application`] boots the full
//! stack around it; frame-host's own binary is the first consumer
//! ([`crate::app`]), the generated scaffold the second.

use frame_core::component::ComponentMeta;
use frame_core::registry::ComponentRegistry;
use frame_core::runtime::RuntimePolicy;
use thiserror::Error;

use crate::announcer::Announcer;

/// A typed failure raised by the embedding application's own hooks (the
/// readiness proof or the fact announcement), carried into
/// [`crate::error::HostError::Application`].
#[derive(Debug, Error)]
#[error("{detail}")]
pub struct AppError {
    detail: String,
}

impl AppError {
    /// Wraps the application's own failure detail.
    #[must_use]
    pub fn new(detail: impl Into<String>) -> Self {
        Self {
            detail: detail.into(),
        }
    }
}

/// One component the application installs: its manifest, its compiled
/// bytecode, and any support (e.g. FFI) modules that must be loaded before
/// the component starts and unloaded in order at teardown.
pub struct ComponentInstall {
    /// The component's full manifest (identity, children, supervision,
    /// declared capability needs).
    pub meta: ComponentMeta,
    /// The component's compiled BEAM bytecode.
    pub bytecode: Vec<u8>,
    /// Compiled support modules loaded before the component starts, in the
    /// given order, and unloaded in reverse order at teardown.
    pub support_modules: Vec<Vec<u8>>,
}

/// The post-start readiness proof, run once before the bus boots: the
/// application's own bounded check that its components are genuinely live
/// (e.g. a mailbox liveness probe).
pub type ReadinessProbe = Box<dyn FnOnce(&ComponentRegistry) -> Result<(), AppError> + Send>;

/// The application's boot-time fact announcement, run once after the
/// announcer connects: the application publishes its own real facts (e.g. a
/// stored entity id) through the announcer.
pub type FactAnnouncement =
    Box<dyn FnOnce(&ComponentRegistry, &Announcer) -> Result<(), AppError> + Send>;

/// Everything an embedding application supplies; frame-host supplies nothing
/// (design §4.2).
pub struct AppSpec {
    /// Component registrations: metadata + component bytecode + support
    /// modules. Must be non-empty — a host with nothing to host is refused
    /// as a typed composition error at boot.
    pub components: Vec<ComponentInstall>,
    /// Runtime policy (threads, operation timeout) — stated by the
    /// application, no defaults.
    pub policy: RuntimePolicy,
    /// Post-start proof run once before the bus boots and serving begins.
    pub readiness: ReadinessProbe,
    /// Application-announced facts, published once the announcer is
    /// connected. Skipped with a loud log when no `[frame].channel` is
    /// declared (no announcer exists to carry them).
    pub announce: FactAnnouncement,
}