forma_server/
ir_compat.rs1use forma_ir::parser::IrModule;
2use forma_ir::IR_VERSION;
3use rust_embed::Embed;
4use std::collections::HashMap;
5
6use crate::{AssetManifest, RenderMode};
7
8pub fn check_ir_compatibility(module: &IrModule) -> Result<(), String> {
10 if module.header.version != IR_VERSION {
11 return Err(format!(
12 "IR version {} is not compatible with runtime version {}",
13 module.header.version, IR_VERSION
14 ));
15 }
16 Ok(())
17}
18
19pub fn load_ir_modules<A: Embed>(
30 manifest: &AssetManifest,
31) -> (HashMap<String, RenderMode>, HashMap<String, IrModule>) {
32 let mut render_modes = HashMap::new();
33 let mut ir_modules = HashMap::new();
34
35 for (route_pattern, route_assets) in &manifest.routes {
36 if let Some(ref ir_filename) = route_assets.ir {
37 if let Some(ir_bytes) = crate::assets::asset_bytes::<A>(ir_filename) {
38 match IrModule::parse(&ir_bytes) {
39 Ok(module) => match check_ir_compatibility(&module) {
40 Ok(()) => {
41 tracing::info!(route = %route_pattern, ir_file = %ir_filename, "Loaded IR module for SSR");
42 render_modes
43 .insert(route_pattern.clone(), RenderMode::Phase2SsrReconcile);
44 ir_modules.insert(route_pattern.clone(), module);
45 }
46 Err(e) => {
47 tracing::warn!(route = %route_pattern, error = %e, "IR compatibility check failed — Phase 1 fallback");
48 render_modes
49 .insert(route_pattern.clone(), RenderMode::Phase1ClientMount);
50 }
51 },
52 Err(e) => {
53 tracing::warn!(route = %route_pattern, error = %e, "Failed to parse IR module — Phase 1 fallback");
54 render_modes.insert(route_pattern.clone(), RenderMode::Phase1ClientMount);
55 }
56 }
57 }
58 }
59 }
60
61 if !ir_modules.is_empty() {
62 tracing::info!(
63 ssr_routes = ir_modules.len(),
64 "Phase 2 SSR enabled for {} route(s)",
65 ir_modules.len()
66 );
67 }
68
69 (render_modes, ir_modules)
70}