pub mod client;
pub mod core;
pub mod exec;
pub mod flow;
pub mod realtime;
pub mod router;
pub mod server;
pub mod ssr;
#[cfg(feature = "cli")]
pub mod cli;
pub use resuma_macros::{
component, computed, data, debounce, effect, island, js, layout, load, middleware, server,
submit, upload, view, worker, Store,
};
pub use crate::client::{
client_component, client_script_path, client_script_url, content_digest,
register_client_asset_digest, ClientComponent, CLIENT_SCRIPT_PREFIX,
};
pub use crate::core::view::AttrValue;
pub use crate::core::{
combine_js, error_boundary, for_signal, for_signal_virtual, gesture_view, match_signal, modal,
modal_trigger, nav_link, no_serialize, popup, popup_anchor, portal, provide_context,
provide_theme, push_slots, resolve_slot, show, show_signal, signal, stream_chunk, stream_slot,
theme_css_vars, theme_switch, try_use_context, use_computed, use_computed_with_js, use_context,
use_debounce, use_effect, use_signal, use_store, use_task, use_theme, use_visible_task,
use_visible_task_with_captures, visible_task_js, with_default_slot, with_view_transition,
Child, Component, Computed, ContextId, Effect, FlowRequest, GestureOpts, HtmlTheme, IntoView,
ModalOpts, NoSerialize, PopupOpts, ReadSignal, RenderContext, RenderMode, Result, ResumaError,
ResumePayload, Signal, SlotGuard, SlottedChild, Store, Theme, View, VisibleTaskSpec,
WriteSignal,
};
pub use crate::server::{
build_content_security_policy, configure_security, register_server_action,
set_action_middleware, set_page_canonical, set_page_description, set_page_dir,
set_page_json_ld, set_page_robots, set_page_theme, set_page_title, stage_response_redirect,
stage_response_status, CspConfig, ResumaApp, SecurityConfig, ServeOptions, CSRF_FIELD,
CSRF_HEADER,
};
pub use crate::ssr::seo_kit::{AiCrawlerPolicy, MetaTag, SeoKit};
pub use crate::ssr::{render_to_stream, render_to_string, render_view, PageOptions};
pub use crate::flow::{
apply_layouts, build_query_href, clear_cookie, collect_public_dir, cookie_value,
current_location_href, current_request, discover_pages, encode_submit_result, error_page,
extract_redirect, flash_message, form, invalidate_href, invalidate_href_now, invalidate_link,
load_all2, load_all3, load_all4, load_boundary, loader_poll, loader_refresh_form,
loader_refresh_input, not_found_page, query_nav_link, redirect, redirect_with_flash,
register_layout, register_loader, register_loader_cache, register_middleware,
register_stream_chunk, register_stream_loader, register_submit, set_cookie,
set_current_request, theme_into_pwa, try_use_load, try_use_load_value, use_load, with_request,
CookieOptions, DiscoveredPage, FlowApp, FlowError, FlowExtensions, FlowPageRegistry,
FlowPwaConfig, FlowServeOptions, FromFlowRequest, LoadValue, LoaderError, Path, PublicAsset,
PwaShortcut, Query, Redirect, SameSite, SubmitError, SubmitValue,
};
pub use crate::realtime::{
classify_frame, spawn_ws_writer, InboundFrame, Peer, PeerId, Room, RoomFull, RoomRegistry,
WsWriter,
};
pub use crate::exec::{
artifact_get, artifact_put, artifact_put_json, attach_exec_routes, dispatch_tool, durable_get,
durable_set, enqueue, init_exec, plan as plan_execution, queue_stats, register_tool,
register_upload, register_worker, resolve_resources, store_upload, take_upload, ArtifactRef,
ExecutionRecord, FlowEngine, GraphId, GraphSnapshot, PlannerHints, QueueMessage, QueueStats,
ResourceProfile, Resources, RuntimeChoice, RuntimeTarget, StartWorkerResponse, UploadMeta,
UploadReceipt, UploadedFile, WorkerContext, WorkerEvent, WorkerMeta, WorkerRegistry,
};
#[cfg(feature = "cli")]
pub fn run() -> anyhow::Result<()> {
crate::cli::run()
}
pub mod prelude {
pub use super::{
build_query_href, clear_cookie, client_component, client_script_url, combine_js, component,
computed, configure_security, cookie_value, current_request, data, debounce, effect,
error_boundary, error_page, extract_redirect, flash_message, for_signal,
for_signal_virtual, form, gesture_view, invalidate_href, invalidate_href_now,
invalidate_link, island, js, layout, load, load_all2, load_all3, load_all4, load_boundary,
loader_poll, loader_refresh_form, loader_refresh_input, match_signal, middleware, modal,
modal_trigger, nav_link, not_found_page, popup, popup_anchor, portal, provide_context,
provide_theme, push_slots, query_nav_link, redirect, redirect_with_flash, render_to_string,
render_view, resolve_slot, server, set_action_middleware, set_cookie, set_page_canonical,
set_page_description, set_page_dir, set_page_json_ld, set_page_robots, set_page_theme,
set_page_title, show, signal, stage_response_redirect, stage_response_status, stream_slot,
submit, theme_css_vars, theme_switch, try_use_context, try_use_load, try_use_load_value,
upload, use_computed, use_computed_with_js, use_context, use_debounce, use_effect,
use_load, use_signal, use_store, use_task, use_theme, use_visible_task,
use_visible_task_with_captures, view, visible_task, with_view_transition, worker,
AttrValue, Child, ClientComponent, Component, Computed, CookieOptions, CspConfig, Effect,
FlowApp, FlowError, FlowPageRegistry, FlowPwaConfig, FlowRequest, FlowServeOptions,
FromFlowRequest, GestureOpts, HtmlTheme, IntoView, LoadValue, LoaderError, ModalOpts,
PageOptions, Path, PopupOpts, PublicAsset, PwaShortcut, Query, ReadSignal, Redirect,
Result, ResumaApp, ResumaError, SameSite, SecurityConfig, SeoKit, ServeOptions, Signal,
SlottedChild, Store, SubmitError, Theme, View, WriteSignal, CLIENT_SCRIPT_PREFIX,
CSRF_FIELD, CSRF_HEADER,
};
}
#[macro_export]
macro_rules! visible_task {
($js:expr $(, $($cap:ident),+ $(,)?)?) => {{
let mut __caps = ::std::collections::BTreeMap::new();
$( $(
__caps.insert(::std::stringify!($cap).to_string(), $cap.id());
)+ )?
$crate::use_visible_task_with_captures($js, __caps)
}};
}
#[doc(hidden)]
pub mod __private {
pub use crate::core::effect::{attach_client_effect, use_computed_with_js, use_effect};
pub use crate::core::task::{register_debounce_effect, use_debounce};
pub use crate::core::{
combine_js, for_signal, for_signal_virtual, gesture_view, match_signal, match_static,
modal, modal_trigger, nav_link, popup, popup_anchor, show, show_signal, theme_switch,
};
pub use crate::core::{
context::{current_context, with_handler_chunk, RenderContext, RenderMode},
handler::{HandlerCapture, HandlerRef},
overlay::{GestureOpts, ModalOpts, PopupOpts},
signal::SignalId,
slot::{push_slots, resolve_slot, with_default_slot, SlottedChild},
view::{AttrValue, Element, Fragment, Island as IslandView},
Child, Component, IntoView, ReadSignal, Result, ResumaError, Signal, View, WriteSignal,
};
pub use crate::flow::form as flow_form;
pub use crate::server::register_server_action;
pub use ctor;
pub use serde;
pub use serde_json;
#[derive(Debug, Clone)]
pub enum HandlerSource {
Inline(String),
Chunk {
chunk: String,
symbol: String,
source: String,
},
}
#[derive(Debug, Clone)]
pub enum ResumeCapture {
Signal { name: String, id: SignalId },
Action(String),
}
pub use crate::core::view::Element as ElementType;
pub fn register_handler(
event: &str,
_chunk: &str,
symbol: &str,
js_source: &str,
captures: Vec<ResumeCapture>,
actions: Vec<String>,
) -> AttrValue {
let chunk = current_context()
.map(|c| c.current_handler_chunk())
.unwrap_or_else(|| "__page__".to_string());
if let Some(ctx) = current_context() {
ctx.register_handler(&chunk, symbol, js_source);
for a in &actions {
ctx.register_action(a);
}
}
let signal_captures: Vec<HandlerCapture> = captures
.into_iter()
.filter_map(|c| match c {
ResumeCapture::Signal { name, id } => Some(HandlerCapture { name, id }),
_ => None,
})
.collect();
let inline = if chunk == "__page__"
&& js_source.len() <= crate::core::context::INLINE_HANDLER_MAX_BYTES
{
Some(js_source.to_string())
} else {
None
};
AttrValue::Handler(HandlerRef {
event: event.to_string(),
chunk,
symbol: symbol.to_string(),
captures: signal_captures,
inline,
})
}
pub trait ElementBuilderExt {
fn attr_runtime(self, kv: (String, AttrValue)) -> Self;
}
impl ElementBuilderExt for crate::core::view::ElementBuilder {
fn attr_runtime(self, (name, value): (String, AttrValue)) -> Self {
self.attr(name, value)
}
}
pub fn render_component<C: Component>(props: C::Props) -> View {
C::render(props)
}
pub fn resolve_attr_value<T: Into<AttrValueAuto>>(value: T) -> AttrValue {
value.into().into_attr_value()
}
pub struct AttrValueAuto(AttrValue);
impl AttrValueAuto {
fn into_attr_value(self) -> AttrValue {
self.0
}
}
impl From<&str> for AttrValueAuto {
fn from(s: &str) -> Self {
Self(AttrValue::Static(s.to_string()))
}
}
impl From<String> for AttrValueAuto {
fn from(s: String) -> Self {
Self(AttrValue::Static(s))
}
}
impl From<bool> for AttrValueAuto {
fn from(b: bool) -> Self {
Self(AttrValue::Static(b.to_string()))
}
}
impl From<i32> for AttrValueAuto {
fn from(n: i32) -> Self {
Self(AttrValue::Static(n.to_string()))
}
}
impl From<i64> for AttrValueAuto {
fn from(n: i64) -> Self {
Self(AttrValue::Static(n.to_string()))
}
}
impl From<u32> for AttrValueAuto {
fn from(n: u32) -> Self {
Self(AttrValue::Static(n.to_string()))
}
}
impl From<u64> for AttrValueAuto {
fn from(n: u64) -> Self {
Self(AttrValue::Static(n.to_string()))
}
}
impl From<f64> for AttrValueAuto {
fn from(n: f64) -> Self {
Self(AttrValue::Static(n.to_string()))
}
}
impl<T: Clone + serde::Serialize + 'static> From<&Signal<T>> for AttrValueAuto {
fn from(s: &Signal<T>) -> Self {
Self(AttrValue::Dynamic {
signal: s.id(),
format: None,
})
}
}
impl<T: Clone + serde::Serialize + 'static> From<Signal<T>> for AttrValueAuto {
fn from(s: Signal<T>) -> Self {
Self(AttrValue::Dynamic {
signal: s.id(),
format: None,
})
}
}
impl<T: Clone + serde::Serialize + Send + Sync + 'static> From<&crate::Computed<T>>
for AttrValueAuto
{
fn from(c: &crate::Computed<T>) -> Self {
Self(AttrValue::Dynamic {
signal: c.id(),
format: None,
})
}
}
pub fn wrap_in_island(
name: &str,
instance: u32,
build: impl FnOnce() -> View,
load: &str,
) -> View {
if let Some(ctx) = current_context() {
ctx.register_island(name);
}
let load = match load {
"visible" | "Visible" => view_mod::IslandLoad::Visible,
_ => view_mod::IslandLoad::Eager,
};
let inner = crate::core::context::with_handler_chunk(name, build);
View::Island(IslandView {
chunk_id: name.to_string(),
instance_id: format!("{}-{}", name, instance),
signal_ids: Vec::new(),
view: Box::new(inner),
props: serde_json::Value::Null,
load,
})
}
pub use crate::core::view as view_mod;
pub use crate::core::view::ElementBuilder;
pub fn fragment(children: Vec<Child>) -> View {
View::fragment(children)
}
pub fn element(tag: &str) -> ElementBuilder {
View::element(tag)
}
}