1pub mod client;
62pub mod core;
63pub mod flow;
64pub mod router;
65pub mod server;
66pub mod ssr;
67
68#[cfg(feature = "cli")]
69pub mod cli;
70
71pub use resuma_macros::{
72 component, computed, data, debounce, effect, island, js, layout, load, middleware, server,
73 submit, view,
74};
75
76pub use crate::client::{
77 client_component, client_script_url, ClientComponent, CLIENT_SCRIPT_PREFIX,
78};
79
80pub use crate::core::{
81 combine_js, error_boundary, nav_link, no_serialize, portal, provide_context, provide_theme,
82 push_slots, resolve_slot, show, signal, stream_chunk, stream_slot, theme_css_vars,
83 use_computed, use_computed_with_js, use_context, use_debounce, use_effect, use_signal,
84 use_store, use_task, use_theme, use_visible_task, visible_task_js, with_default_slot,
85 with_view_transition, Child, Component, Computed, ContextId, Effect, FlowRequest, IntoView,
86 NoSerialize, ReadSignal, RenderContext, RenderMode, Result, ResumaError, ResumePayload, Signal,
87 SlotGuard, SlottedChild, Store, Theme, View, WriteSignal,
88};
89
90pub use crate::server::{
91 configure_security, register_server_action, set_action_middleware, ResumaApp, SecurityConfig,
92 ServeOptions, CSRF_FIELD, CSRF_HEADER,
93};
94
95pub use crate::ssr::{render_to_stream, render_to_string, render_view, PageOptions};
96
97pub use crate::flow::{
98 apply_layouts, current_request, discover_pages, encode_submit_result, error_page,
99 extract_redirect, flash_message, form, load_boundary, not_found_page, redirect,
100 redirect_with_flash, register_layout, register_loader, register_loader_cache,
101 register_middleware, register_stream_chunk, register_stream_loader, register_submit,
102 try_use_load, try_use_load_value, use_load, with_request, DiscoveredPage, FlowApp, FlowError,
103 FlowExtensions, FlowPageRegistry, FlowPwaConfig, FlowServeOptions, LoadValue, LoaderError,
104 Redirect, SubmitError, SubmitValue,
105};
106
107#[cfg(feature = "cli")]
109pub fn run() -> anyhow::Result<()> {
110 crate::cli::run()
111}
112
113pub mod prelude {
114 pub use super::{
136 client_component, client_script_url, combine_js, component, computed, configure_security,
137 current_request, data, debounce, effect, error_boundary, error_page, extract_redirect,
138 flash_message, form, island, js, layout, load, load_boundary, middleware, nav_link,
139 not_found_page, portal, provide_context, provide_theme, push_slots, redirect,
140 redirect_with_flash, render_to_string, render_view, resolve_slot, server,
141 set_action_middleware, show, signal, stream_slot, submit, theme_css_vars, try_use_load,
142 try_use_load_value, use_computed, use_computed_with_js, use_context, use_debounce,
143 use_effect, use_load, use_signal, use_store, use_task, use_theme, use_visible_task, view,
144 with_view_transition, Child, ClientComponent, Component, Computed, Effect, FlowApp,
145 FlowError, FlowPageRegistry, FlowRequest, FlowServeOptions, IntoView, LoadValue,
146 LoaderError, PageOptions, ReadSignal, Redirect, Result, ResumaApp, ResumaError,
147 SecurityConfig, ServeOptions, Signal, SlottedChild, Store, SubmitError, Theme, View,
148 WriteSignal, CLIENT_SCRIPT_PREFIX, CSRF_FIELD, CSRF_HEADER,
149 };
150}
151
152#[doc(hidden)]
153pub mod __private {
154 pub use crate::core::effect::{attach_client_effect, use_computed_with_js};
156 pub use crate::core::task::register_debounce_effect;
157 pub use crate::core::{combine_js, nav_link, show};
158 pub use crate::core::{
159 context::{current_context, with_handler_chunk, RenderContext, RenderMode},
160 handler::{HandlerCapture, HandlerRef},
161 signal::SignalId,
162 slot::{push_slots, resolve_slot, with_default_slot, SlottedChild},
163 view::{AttrValue, Element, Fragment, Island as IslandView},
164 Child, Component, IntoView, ReadSignal, Result, ResumaError, Signal, View, WriteSignal,
165 };
166 pub use crate::flow::form as flow_form;
167 pub use crate::server::register_server_action;
168 pub use ctor;
169 pub use serde;
170 pub use serde_json;
171
172 #[derive(Debug, Clone)]
173 pub enum HandlerSource {
174 Inline(String),
175 Chunk {
176 chunk: String,
177 symbol: String,
178 source: String,
179 },
180 }
181
182 #[derive(Debug, Clone)]
183 pub enum ResumeCapture {
184 Signal { name: String, id: SignalId },
185 Action(String),
186 }
187
188 pub use crate::core::view::Element as ElementType;
189
190 pub fn register_handler(
191 event: &str,
192 _chunk: &str,
193 symbol: &str,
194 js_source: &str,
195 captures: Vec<ResumeCapture>,
196 actions: Vec<String>,
197 ) -> AttrValue {
198 let chunk = current_context()
199 .map(|c| c.current_handler_chunk())
200 .unwrap_or_else(|| "__page__".to_string());
201
202 if let Some(ctx) = current_context() {
203 ctx.register_handler(&chunk, symbol, js_source);
204 for a in &actions {
205 ctx.register_action(a);
206 }
207 }
208
209 let signal_captures: Vec<HandlerCapture> = captures
210 .into_iter()
211 .filter_map(|c| match c {
212 ResumeCapture::Signal { name, id } => Some(HandlerCapture { name, id }),
213 _ => None,
214 })
215 .collect();
216
217 let inline = if chunk == "__page__"
218 && js_source.len() <= crate::core::context::INLINE_HANDLER_MAX_BYTES
219 {
220 Some(js_source.to_string())
221 } else {
222 None
223 };
224
225 AttrValue::Handler(HandlerRef {
226 event: event.to_string(),
227 chunk,
228 symbol: symbol.to_string(),
229 captures: signal_captures,
230 inline,
231 })
232 }
233
234 pub trait ElementBuilderExt {
235 fn attr_runtime(self, kv: (String, AttrValue)) -> Self;
236 }
237
238 impl ElementBuilderExt for crate::core::view::ElementBuilder {
239 fn attr_runtime(self, (name, value): (String, AttrValue)) -> Self {
240 self.attr(name, value)
241 }
242 }
243
244 pub fn render_component<C: Component>(props: C::Props) -> View {
245 C::render(props)
246 }
247
248 pub fn resolve_attr_value<T: Into<AttrValueAuto>>(value: T) -> AttrValue {
249 value.into().into_attr_value()
250 }
251
252 pub struct AttrValueAuto(AttrValue);
253
254 impl AttrValueAuto {
255 fn into_attr_value(self) -> AttrValue {
256 self.0
257 }
258 }
259
260 impl From<&str> for AttrValueAuto {
261 fn from(s: &str) -> Self {
262 Self(AttrValue::Static(s.to_string()))
263 }
264 }
265 impl From<String> for AttrValueAuto {
266 fn from(s: String) -> Self {
267 Self(AttrValue::Static(s))
268 }
269 }
270 impl From<bool> for AttrValueAuto {
271 fn from(b: bool) -> Self {
272 Self(AttrValue::Static(b.to_string()))
273 }
274 }
275 impl From<i32> for AttrValueAuto {
276 fn from(n: i32) -> Self {
277 Self(AttrValue::Static(n.to_string()))
278 }
279 }
280 impl From<i64> for AttrValueAuto {
281 fn from(n: i64) -> Self {
282 Self(AttrValue::Static(n.to_string()))
283 }
284 }
285 impl From<u32> for AttrValueAuto {
286 fn from(n: u32) -> Self {
287 Self(AttrValue::Static(n.to_string()))
288 }
289 }
290 impl From<u64> for AttrValueAuto {
291 fn from(n: u64) -> Self {
292 Self(AttrValue::Static(n.to_string()))
293 }
294 }
295 impl From<f64> for AttrValueAuto {
296 fn from(n: f64) -> Self {
297 Self(AttrValue::Static(n.to_string()))
298 }
299 }
300
301 impl<T: Clone + serde::Serialize + 'static> From<&Signal<T>> for AttrValueAuto {
302 fn from(s: &Signal<T>) -> Self {
303 Self(AttrValue::Dynamic {
304 signal: s.id(),
305 format: None,
306 })
307 }
308 }
309 impl<T: Clone + serde::Serialize + 'static> From<Signal<T>> for AttrValueAuto {
310 fn from(s: Signal<T>) -> Self {
311 Self(AttrValue::Dynamic {
312 signal: s.id(),
313 format: None,
314 })
315 }
316 }
317
318 pub fn wrap_in_island(name: &str, instance: u32, view: View, load: &str) -> View {
319 if let Some(ctx) = current_context() {
320 ctx.register_island(name);
321 }
322 let load = match load {
323 "visible" | "Visible" => view_mod::IslandLoad::Visible,
324 _ => view_mod::IslandLoad::Eager,
325 };
326 let inner = crate::core::context::with_handler_chunk(name, || view);
327 View::Island(IslandView {
328 chunk_id: name.to_string(),
329 instance_id: format!("{}-{}", name, instance),
330 signal_ids: Vec::new(),
331 view: Box::new(inner),
332 props: serde_json::Value::Null,
333 load,
334 })
335 }
336
337 pub use crate::core::view as view_mod;
338 pub use crate::core::view::ElementBuilder;
339
340 pub fn fragment(children: Vec<Child>) -> View {
341 View::fragment(children)
342 }
343
344 pub fn element(tag: &str) -> ElementBuilder {
345 View::element(tag)
346 }
347}