Skip to main content

seam_server/build_loader/
types.rs

1/* src/server/core/rust/src/build_loader/types.rs */
2
3use std::collections::HashMap;
4
5use serde::Deserialize;
6
7#[derive(Deserialize)]
8pub(super) struct RouteManifest {
9	#[serde(default)]
10	pub(super) layouts: HashMap<String, LayoutEntry>,
11	pub(super) routes: HashMap<String, RouteEntry>,
12	#[serde(default)]
13	pub(super) data_id: Option<String>,
14	#[serde(default)]
15	pub(super) i18n: Option<I18nManifest>,
16}
17
18#[derive(Deserialize)]
19pub(super) struct I18nManifest {
20	#[serde(default)]
21	pub(super) locales: Vec<String>,
22	#[serde(default)]
23	pub(super) default: String,
24	#[serde(default)]
25	pub(super) mode: Option<String>,
26	#[serde(default)]
27	pub(super) cache: bool,
28	#[serde(default)]
29	pub(super) route_hashes: HashMap<String, String>,
30	#[serde(default)]
31	pub(super) content_hashes: HashMap<String, HashMap<String, String>>,
32}
33
34#[derive(Deserialize)]
35pub(super) struct LayoutEntry {
36	pub(super) template: Option<String>,
37	#[serde(default)]
38	pub(super) templates: Option<HashMap<String, String>>,
39	#[serde(default)]
40	pub(super) loaders: serde_json::Value,
41	#[serde(default)]
42	pub(super) parent: Option<String>,
43	#[serde(default)]
44	pub(super) i18n_keys: Vec<String>,
45}
46
47#[derive(Deserialize)]
48pub(super) struct RouteEntry {
49	pub(super) template: Option<String>,
50	#[serde(default)]
51	pub(super) templates: Option<HashMap<String, String>>,
52	#[serde(default)]
53	pub(super) layout: Option<String>,
54	#[serde(default)]
55	pub(super) loaders: serde_json::Value,
56	#[serde(default)]
57	pub(super) derives: Option<serde_json::Value>,
58	#[serde(default)]
59	pub(super) head_meta: Option<String>,
60	#[serde(default)]
61	pub(super) i18n_keys: Vec<String>,
62	#[serde(default)]
63	pub(super) projections: Option<HashMap<String, Vec<String>>>,
64	#[serde(default)]
65	pub(super) prerender: Option<bool>,
66}
67
68/// Pick a template path: prefer singular `template`, fall back to default locale or first value.
69pub(super) fn pick_template(
70	single: &Option<String>,
71	multi: &Option<HashMap<String, String>>,
72	default_locale: Option<&str>,
73) -> Option<String> {
74	if let Some(t) = single {
75		return Some(t.clone());
76	}
77	if let Some(map) = multi {
78		// Prefer the default locale from manifest
79		if let Some(loc) = default_locale
80			&& let Some(t) = map.get(loc)
81		{
82			return Some(t.clone());
83		}
84		return map.values().next().cloned();
85	}
86	None
87}
88
89#[derive(Deserialize)]
90pub(super) struct LoaderConfig {
91	pub(super) procedure: String,
92	#[serde(default)]
93	pub(super) params: HashMap<String, ParamConfig>,
94}
95
96/// Supports both string shorthand `"route"` and full object `{ "from": "route", "type": "int" }`.
97pub(super) struct ParamConfig {
98	pub(super) from: String,
99	pub(super) param_type: String,
100}
101
102pub(super) fn default_type() -> String {
103	"string".to_string()
104}
105
106impl<'de> serde::Deserialize<'de> for ParamConfig {
107	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108	where
109		D: serde::Deserializer<'de>,
110	{
111		let value = serde_json::Value::deserialize(deserializer)?;
112		match value {
113			serde_json::Value::String(s) => Ok(ParamConfig { from: s, param_type: default_type() }),
114			serde_json::Value::Object(map) => {
115				let from = map
116					.get("from")
117					.and_then(|v| v.as_str())
118					.ok_or_else(|| serde::de::Error::missing_field("from"))?
119					.to_string();
120				let param_type =
121					map.get("type").and_then(|v| v.as_str()).map(String::from).unwrap_or_else(default_type);
122				Ok(ParamConfig { from, param_type })
123			}
124			_ => Err(serde::de::Error::custom("expected string or object")),
125		}
126	}
127}
128
129/// RPC hash map loaded from build output. Maps hashed names back to original procedure names.
130#[derive(Deserialize, Clone, Debug)]
131pub struct RpcHashMap {
132	pub salt: String,
133	pub batch: String,
134	pub procedures: HashMap<String, String>,
135}
136
137impl RpcHashMap {
138	/// Build a reverse lookup: hash -> original name
139	pub fn reverse_lookup(&self) -> HashMap<String, String> {
140		self.procedures.iter().map(|(name, hash)| (hash.clone(), name.clone())).collect()
141	}
142}