Skip to main content

forma_server/
lib.rs

1//! Typed server rendering and explicit browser shells for Forma.
2//!
3//! Load the build's validated manifest and modules, bind every SSR route to its
4//! derived handler, then call [`Pages::finalize`] before opening the listener.
5//! [`PageHandle::render`] returns a [`PageResponse`] or a coded [`RenderError`];
6//! it never substitutes a browser shell for a failure.
7//!
8//! ```no_run
9//! use forma_ir::PageProps;
10//! use forma_server::{assets, load_ir_modules, PageHandle, RenderCtx};
11//! #[derive(PageProps)]
12//! struct HomeProps { title: String }
13//! fn start<A: rust_embed::Embed + 'static>() -> Result<PageHandle<HomeProps>, String> {
14//!     let manifest = assets::try_load_manifest::<A>()?;
15//!     let pages = load_ir_modules::<A>(&manifest).map_err(|e| format!("{e:?}"))?;
16//!     let home = pages.bind("home").map_err(|e| format!("{e:?}"))?;
17//!     pages.finalize().map_err(|e| format!("{e:?}"))?;
18//!     Ok(home) // the application may now open its listener
19//! }
20//! fn home(page: &PageHandle<HomeProps>) -> Result<forma_server::PageResponse, forma_server::RenderError> {
21//!     page.render(&HomeProps { title:"Hello".into() }, &RenderCtx::new())
22//! }
23//! ```
24//!
25//! The response keeps HTML, its fresh nonce, enforced CSP and no-store headers
26//! together. Per-request [`RenderCtx`] carries typed policy/head/preload settings,
27//! escaped JSON, branding CSS and an explicit [`RawHtml`] prefix, never a nonce
28//! or executable handler script. [`render_browser_shell`] accepts only a route
29//! explicitly declared Browser. Unreviewed content belongs in [`frame`].
30//!
31//! In debug builds a corrupt edit keeps the previous module/asset snapshot;
32//! changed schemas are rebound, while changed route names or modes require a
33//! restart and fresh finalization. Release builds use their embedded snapshot.
34//! The old raw SSR entry, tuple loader, PageOutput and caller nonce API are gone.
35
36// Makes README.md's and SECURITY.md's "Zero `unsafe` blocks" a property the
37// compiler enforces rather than a claim.
38#![forbid(unsafe_code)]
39// No `unwrap`, `expect` or `panic!` in the code that ships (DR-12, SR44): a
40// render returns its failure. Tests may. The 0.2.1 functions whose signatures
41// have no room for an error (`CspNonce::generate`, `assets::asset`, the
42// deprecated `assets::load_manifest`) keep their documented panics under a
43// scoped `allow`, each with its fallible twin; none is on the render path.
44#![cfg_attr(
45    not(test),
46    deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)
47)]
48
49/// Serving content-hashed files out of the embedded `dist` directory.
50pub mod assets;
51/// Content-Security-Policy construction and nonce generation.
52pub mod csp;
53/// Compile controls pinning removed response/raw-script bridges.
54#[cfg(doctest)]
55mod deprecations;
56// Documented by its own `//!` docs (the preview frame, DR-14 tier (c)).
57pub mod frame;
58/// Typed homes for the page's head: manifest preloads and head links.
59pub mod head;
60/// Loading and version-checking the per-route `.ir` modules at startup.
61pub mod ir;
62/// Bound page contracts and checked handler rendering.
63pub mod pages;
64/// Raw HTML: the one named type for markup written unescaped.
65pub mod raw;
66/// Request context, errors and the explicit browser shell.
67pub mod render;
68/// The page response: HTML that never leaves without its policy.
69pub mod response;
70// Documented by its own `//!` docs: an outer `///` line here would merge with
71// them and resolve their intra-doc links from the crate root.
72pub mod sw;
73/// The HTML page template and the SSR render entry points.
74pub mod template;
75/// Document metadata, manifest and declared route modes.
76pub mod types;
77
78/// Re-exported because it appears in [`assets::asset_bytes`]'s signature.
79pub use axum::body::Bytes;
80pub use csp::{
81    build_csp_header, generate_csp_nonce, CspNonce, InvalidNonce, NonceError, PolicyError,
82    PolicyExtensions,
83};
84pub use forma_ir::props::{PropsError, PropsSource, PropsWarning};
85/// Parser errors and their authoritative `code()` method.
86pub use forma_ir::IrError;
87/// Derive and trait for declared handler props.
88pub use forma_ir::PageProps;
89/// Re-exported: [`RenderCtx::with_limits`] takes it.
90pub use forma_ir::WalkLimits;
91/// Limits inherited by a bound page, with optional per-request overrides.
92pub use forma_ir::WalkLimits as Limits;
93pub use frame::{FrameError, PreviewFrame, FRAME_RUNTIME_ASSET};
94pub use head::{HeadLink, HeadLinkError, ModulePreloads};
95#[allow(deprecated)]
96pub use ir::{load_ir_modules, IrLoadError};
97pub use pages::{PageHandle, Pages};
98pub use raw::RawHtml;
99pub use render::{render_browser_shell, RenderCtx, RenderError};
100pub use response::{PageParts, PageResponse, RenderCounts};
101pub use types::*;
102
103#[cfg(test)]
104#[path = "../tests/internal_renderer/mod.rs"]
105mod render_contract;