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::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. Public asset/manifest loading and
41// nonce generation also return their errors, including the compatibility aliases.
42#![cfg_attr(
43    not(test),
44    deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)
45)]
46
47/// Serving content-hashed files out of the embedded `dist` directory.
48pub mod assets;
49/// Content-Security-Policy construction and nonce generation.
50pub mod csp;
51/// Compile controls pinning removed response/raw-script bridges.
52#[cfg(doctest)]
53mod deprecations;
54// Documented by its own `//!` docs (the preview frame, DR-14 tier (c)).
55pub mod frame;
56/// Typed homes for the page's head: manifest preloads and head links.
57pub mod head;
58/// Loading and version-checking the per-route `.ir` modules at startup.
59pub mod ir;
60/// Bound page contracts and checked handler rendering.
61pub mod pages;
62/// Raw HTML: the one named type for markup written unescaped.
63pub mod raw;
64/// Request context, errors and the explicit browser shell.
65pub mod render;
66/// The page response: HTML that never leaves without its policy.
67pub mod response;
68// Documented by its own `//!` docs: an outer `///` line here would merge with
69// them and resolve their intra-doc links from the crate root.
70pub mod sw;
71/// The HTML page template and the SSR render entry points.
72pub mod template;
73/// Document metadata, manifest and declared route modes.
74pub mod types;
75
76/// Re-exported because it appears in [`assets::asset_bytes`]'s signature.
77pub use axum::body::Bytes;
78pub use csp::{
79    build_csp_header, generate_csp_nonce, CspNonce, InvalidNonce, NonceError, PolicyError,
80    PolicyExtensions,
81};
82pub use forma_ir::props::{PropsError, PropsSource, PropsWarning};
83/// Parser errors and their authoritative `code()` method.
84pub use forma_ir::IrError;
85/// Derive and trait for declared handler props.
86pub use forma_ir::PageProps;
87/// Re-exported: [`RenderCtx::with_limits`] takes it.
88pub use forma_ir::WalkLimits;
89/// Limits inherited by a bound page, with optional per-request overrides.
90pub use forma_ir::WalkLimits as Limits;
91pub use frame::{FrameError, PreviewFrame, FRAME_RUNTIME_ASSET};
92pub use head::{HeadLink, HeadLinkError, ModulePreloads};
93#[allow(deprecated)]
94pub use ir::{load_ir_modules, IrLoadError};
95pub use pages::{PageHandle, Pages};
96pub use raw::RawHtml;
97pub use render::{render_browser_shell, RenderCtx, RenderError};
98pub use response::{PageParts, PageResponse, RenderCounts};
99pub use types::*;
100
101#[cfg(test)]
102#[path = "../tests/internal_renderer/mod.rs"]
103mod render_contract;