Sign in

    mizchi/sol/router does not have a README file

    App

    using @mizchi/mars { type Server as App }

    Mars app type alias

    AsyncPageResolver

    Async page resolver type - returns ServerNode for async server components

    Ctx

    using @mizchi/mars { type Context as Ctx }

    Mars context type alias

    AnalyzedRoute

    pub(all) struct AnalyzedRoute {
    pattern : String
    kind : RouteKind
    reason : String
    }

    Analyzed route information

    ApiHandler

    pub(all) struct ApiHandler(async (PageProps) -> Json)

    API handler type - async function that receives PageProps and returns Json response. Uses MoonBit's built-in Json type for wasm/native compatibility.

    ApiHandlerFactory

    pub(all) struct ApiHandlerFactory((
    RouteEntry
    ) -> ApiHandler?)

    Handler factory type - creates an ApiHandler from a route entry Returns None if this factory cannot handle the entry

    ApiResponse

    pub(all) enum ApiResponse {
    Json(Json)
    Redirect(String, Int)
    NotFound(String)
    Error(String, Int)
    }

    Type-safe API response enum

    Use with .to_json() to convert to Json for handler return.

    ApiResponse::to_json

    fn ApiResponse::to_json(self : ApiResponse) -> Json

    Convert ApiResponse to Json for handler return

    CacheStrategy

    pub(all) enum CacheStrategy {
    AlwaysFetch
    StaleWhileRevalidate
    } derive(Eq, Show)

    Cache strategy for CSR navigation Controls how the client handles navigation to the same page

    CacheStrategy::default

    fn CacheStrategy::default() -> CacheStrategy

    Default cache strategy is AlwaysFetch

    CatchAllInfo

    pub(all) struct CatchAllInfo {
    name : String
    optional : Bool
    }

    Catch-all parameter info

    ChunkManifest

    pub struct ChunkManifest {
    entries : Map[String, ChunkManifestEntry]
    base_url : String
    }

    Chunk manifest - maps entry names to their output info Used to resolve shared chunk dependencies for preloading

    ChunkManifest::add

    fn ChunkManifest::add(self : ChunkManifest, name : String, entry : ChunkManifestEntry) -> Unit

    Add entry to manifest

    ChunkManifest::empty

    Create empty chunk manifest

    ChunkManifest::get_chunks

    fn ChunkManifest::get_chunks(self : ChunkManifest, entry_url : String) -> Array[String]

    Get all chunk URLs for an entry (including dependencies)

    ChunkManifest::new

    fn ChunkManifest::new(base_url : String) -> ChunkManifest

    Create chunk manifest with base URL

    ChunkManifest::parse

    fn ChunkManifest::parse(json_str : String, base_url : String) -> ChunkManifest?

    Parse chunk manifest from JSON string (Rolldown/Vite format)

    ChunkManifestEntry

    pub struct ChunkManifestEntry {
    file : String
    imports : Array[String]
    }

    Chunk manifest entry (from Rolldown/Vite manifest.json) Maps entry files to their output chunks and dependencies

    ChunkManifestEntry::new

    fn ChunkManifestEntry::new(file : String, imports : Array[String]) -> ChunkManifestEntry

    Create a chunk manifest entry

    CompiledSolRoute

    pub struct CompiledSolRoute {
    pattern : String
    param_names : Array[String]
    page_handler : PageHandler?
    api_handler : ApiHandler?
    layouts : Array[(PageProps,
    ServerNode
    ) ->
    ServerNode
    raise]
    middlewares : Array[
    Middleware
    ]
    kind : SolRouteKind
    title : String
    meta : Array[(String, String)]
    catch_all : CatchAllInfo?
    revalidate : Int?
    cache_strategy : CacheStrategy
    rendered_meta : String
    }

    Compiled route for efficient matching

    MbtxChunkEntry

    pub(all) struct MbtxChunkEntry {
    id : String
    code : String
    }

    A single entry after chunk splitting

    MbtxChunkResult

    pub(all) struct MbtxChunkResult {
    shared_code : String
    entries : Array[MbtxChunkEntry]
    }

    Result of chunk splitting

    MbtxEntry

    pub(all) struct MbtxEntry {
    id : String
    code : String
    }

    Input entry for chunk splitting

    MbtxResponse

    type MbtxResponse

    Result from mbtx execution

    MbtxRoute

    pub(all) struct MbtxRoute {
    path : String
    js_path : String
    }

    Configuration for a .mbtx route

    PageHandler

    pub(all) struct PageHandler(async (PageProps) ->
    ServerNode
    )

    Page handler type - async function that receives PageProps and returns ServerNode

    PageHandlerFactory

    pub(all) struct PageHandlerFactory((
    RouteEntry
    ) -> PageHandler?)

    Handler factory type - creates a PageHandler from a route entry Returns None if this factory cannot handle the entry

    PageProps

    pub struct PageProps {
    params : RouteParams
    is_fragment : Bool
    is_isr_render : Bool
    // private fields
    }

    Props passed to page components

    PageProps::body_as

    async fn[T :
    FromJson
    ] PageProps::body_as(self : PageProps) -> Result[T, ApiResponse]

    Parse request body as a typed struct via FromJson. Returns Err(ApiResponse) on parse failure (400 Bad Request).

    PageProps::body_json

    async fn PageProps::body_json(self : PageProps) -> Json?

    Parse request body as JSON. Returns None during ISR render to avoid caching request-specific bodies.

    PageProps::cookie

    fn PageProps::cookie(self : PageProps, name : String) -> String?

    Get cookie value by name. Returns None during ISR render to avoid leaking request-specific data.

    PageProps::from_ctx_with_params

    fn PageProps::from_ctx_with_params(ctx :
    Context
    , params : RouteParams) -> PageProps

    Create PageProps from context and pre-extracted params Use this when params are already extracted by the router

    PageProps::get_param

    fn PageProps::get_param(self : PageProps, key : String) -> String?

    Get path parameter by name (convenience method)

    PageProps::get_pathname_group

    fn PageProps::get_pathname_group(self : PageProps, name : String) -> String?

    Get pathname group from URLPatternResult (convenience method)

    PageProps::get_query

    fn PageProps::get_query(self : PageProps, key : String) -> String?

    Get query parameter by name (convenience method)

    PageProps::get_search_group

    fn PageProps::get_search_group(self : PageProps, name : String) -> String?

    Get search group from URLPatternResult (convenience method)

    PageProps::header

    fn PageProps::header(self : PageProps, name : String) -> String?

    Get request header. Returns None during ISR render to avoid leaking request-specific data.

    PageProps::html

    fn PageProps::html(self : PageProps, body : String, status? : Int) -> Unit

    Send an HTML response. No-op during ISR render to keep shared HTML generation side-effect free.

    PageProps::path

    fn PageProps::path(self : PageProps) -> String

    Get the full path

    PageProps::raw_header

    fn PageProps::raw_header(self : PageProps, name : String) -> String?

    Get raw request header. Returns None during ISR render to avoid leaking request-specific data.

    PageProps::set_header

    fn PageProps::set_header(self : PageProps, name : String, value : String) -> Unit

    Set response header.

    PageProps::set_status

    fn PageProps::set_status(self : PageProps, status : Int) -> Unit

    Set response status code. No-op during ISR render to keep shared HTML generation side-effect free.

    PageProps::text

    fn PageProps::text(self : PageProps, body : String, status? : Int) -> Unit

    Send a text response. No-op during ISR render to keep shared HTML generation side-effect free.

    RouteKind

    pub(all) enum RouteKind {
    Static
    Dynamic
    }

    Classification of a route for static/dynamic handling

    RouteParams

    pub struct RouteParams {
    params : Array[(String, String)]
    query : Array[(String, String)]
    path : String
    is_fragment : Bool
    }

    Route parameters extracted from URL

    RouteParams::empty

    fn RouteParams::empty() -> RouteParams

    Create empty route params

    RouteParams::get_param

    fn RouteParams::get_param(self : RouteParams, key : String) -> String?

    Get path parameter by name

    RouteParams::get_pathname_group

    fn RouteParams::get_pathname_group(self : RouteParams, _name : String) -> String?

    Get pathname group from URLPatternResult (JS-only) Returns None — URLPatternResult was removed from RouteParams for native compat. Use RouteParams::get_param() instead for portable code.

    RouteParams::get_query

    fn RouteParams::get_query(self : RouteParams, key : String) -> String?

    Get query parameter by name

    RouteParams::get_search_group

    fn RouteParams::get_search_group(self : RouteParams, _name : String) -> String?

    Get search group from URLPatternResult (JS-only) Returns None — URLPatternResult was removed from RouteParams for native compat. Use RouteParams::get_query() instead for portable code.

    RouteParams::optional

    fn RouteParams::optional(self : RouteParams, name : String, default : String) -> String

    Extract an optional path parameter with default value

    RouteParams::optional_query

    fn RouteParams::optional_query(self : RouteParams, name : String, default : String) -> String

    Extract an optional query parameter with default value

    RouteParams::require

    fn RouteParams::require(self : RouteParams, name : String) -> Result[String, ApiResponse]

    Extract a required path parameter, returning ApiResponse error if missing

    RouteParams::require_int

    fn RouteParams::require_int(self : RouteParams, name : String) -> Result[Int, ApiResponse]

    Extract and parse an integer path parameter

    RouteParams::require_query

    fn RouteParams::require_query(self : RouteParams, name : String) -> Result[String, ApiResponse]

    Extract a required query parameter

    RouterConfig

    pub struct RouterConfig {
    title_prefix : String
    default_title : String
    default_head : String
    loader_url : String
    wc_loader_url : String
    enable_preload : Bool
    enable_streaming : Bool
    preload_libs : Array[String]
    chunk_manifest : ChunkManifest?
    root_template : String
    isr_cache :
    MemoryCache
    ?
    cache_strategy :
    CDNCacheStrategy
    ?
    server_islands : ServerIslandRegistry?
    }

    Router configuration for customizing routing behavior

    RouterConfig::default

    fn RouterConfig::default() -> RouterConfig

    Create default router configuration

    RouterConfig::with_cache_strategy

    Set cache strategy for ISR pages

    RouterConfig::with_chunk_manifest

    fn RouterConfig::with_chunk_manifest(self : RouterConfig, manifest : ChunkManifest) -> RouterConfig

    Set chunk manifest for resolving shared chunk dependencies

    RouterConfig::with_default_head

    fn RouterConfig::with_default_head(self : RouterConfig, head : String) -> RouterConfig

    Set default head HTML

    RouterConfig::with_default_title

    fn RouterConfig::with_default_title(self : RouterConfig, title : String) -> RouterConfig

    Set default title

    RouterConfig::with_isr_cache

    Set ISR cache for incremental static regeneration

    RouterConfig::with_loader_url

    fn RouterConfig::with_loader_url(self : RouterConfig, url : String) -> RouterConfig

    Set loader URL

    RouterConfig::with_preload_libs

    fn RouterConfig::with_preload_libs(self : RouterConfig, libs : Array[String]) -> RouterConfig

    Add library URLs to preload

    RouterConfig::with_root_template

    fn RouterConfig::with_root_template(self : RouterConfig, template : String) -> RouterConfig

    Set root HTML template Template placeholders:
    • LUNA_TITLE : Page title
    • LUNA_PRELOAD : Modulepreload tags
    • LUNA_HEAD : Custom head HTML
    • LUNA_MAIN : Main content

    RouterConfig::with_server_islands

    fn RouterConfig::with_server_islands(self : RouterConfig, registry : ServerIslandRegistry) -> RouterConfig

    Set server island registry for deferred rendering

    RouterConfig::with_streaming_ssr

    fn RouterConfig::with_streaming_ssr(self : RouterConfig, enabled? : Bool) -> RouterConfig

    Enable/disable streaming SSR for full-page responses.

    RouterConfig::with_title_prefix

    fn RouterConfig::with_title_prefix(self : RouterConfig, prefix : String) -> RouterConfig

    Set title prefix

    RouterConfig::with_wc_loader_url

    fn RouterConfig::with_wc_loader_url(self : RouterConfig, url : String) -> RouterConfig

    Set Web Components loader URL

    ServerIslandDef

    pub(all) struct ServerIslandDef {
    id : String
    render : async (Json) ->
    ServerNode

    revalidate : Int?
    }

    Definition of a server island component

    ServerIslandRegistry

    pub(all) struct ServerIslandRegistry {
    islands : Map[String, ServerIslandDef]
    }

    Registry of server island components

    ServerIslandRegistry::get

    Get a server island definition by ID

    ServerIslandRegistry::is_empty

    fn ServerIslandRegistry::is_empty(self : ServerIslandRegistry) -> Bool

    Check if the registry has any islands registered

    ServerIslandRegistry::new

    Create an empty server island registry

    ServerIslandRegistry::register

    fn ServerIslandRegistry::register(self : ServerIslandRegistry, def : ServerIslandDef) -> Unit

    Register a server island component

    SolRouteKind

    pub enum SolRouteKind {
    Page
    GetApi
    PostApi
    PutApi
    DeleteApi
    PatchApi
    } derive(Eq, Show)

    Route kind

    SolRoutes

    pub(all) enum SolRoutes {
    Page(String, PageHandler, String, Array[(String, String)], Int?, CacheStrategy?)
    Layout(String, (PageProps,
    ServerNode
    ) ->
    ServerNode
    raise, Array[SolRoutes])
    Get(String, ApiHandler)
    Post(String, ApiHandler)
    Put(String, ApiHandler)
    Delete(String, ApiHandler)
    Patch(String, ApiHandler)
    WithMiddleware(Array[
    Middleware
    ], Array[SolRoutes])
    }

    Sol route definition with typed handlers

    StaticDir

    pub(all) struct StaticDir {
    path_prefix : String
    source_dir : String
    title : String
    config : StaticDirConfig
    }

    Static directory route definition

    StaticDirConfig

    pub(all) struct StaticDirConfig {
    i18n :
    I18nConfig

    navigation :
    NavigationConfig

    exclude : Array[String]
    trailing_slash : Bool
    }

    Configuration for static directory generation (minimal, backend-independent)

    StaticDirConfig::default

    Default static directory configuration

    analyze_routes

    fn analyze_routes(routes : Array[SolRoutes]) -> Array[AnalyzedRoute]

    Analyze SolRoutes and extract all routes with their classification

    api_delete

    fn[T : ToJson] api_delete(path : String, handler : async (PageProps) -> T) -> SolRoutes

    Create a DELETE API route

    api_get

    fn[T : ToJson] api_get(path : String, handler : async (PageProps) -> T) -> SolRoutes

    Create a GET API route

    Example:
    api_get("/api/users/:id", get_user)

    api_patch

    fn[T : ToJson] api_patch(path : String, handler : async (PageProps) -> T) -> SolRoutes

    Create a PATCH API route

    api_post

    fn[T : ToJson] api_post(path : String, handler : async (PageProps) -> T) -> SolRoutes

    Create a POST API route

    Example:
    api_post("/api/users", create_user)

    api_put

    fn[T : ToJson] api_put(path : String, handler : async (PageProps) -> T) -> SolRoutes

    Create a PUT API route

    bad_request

    fn bad_request(message : String) -> ApiResponse

    Create a bad request (400) response

    combine_api_factories

    fn combine_api_factories(factories : Array[ApiHandlerFactory]) -> ApiHandlerFactory

    Combine multiple API factories into one Tries each factory in order until one returns a handler

    combine_page_factories

    fn combine_page_factories(factories : Array[PageHandlerFactory]) -> PageHandlerFactory

    Combine multiple page factories into one Tries each factory in order until one returns a handler

    compile_sol_routes

    fn compile_sol_routes(routes : Array[SolRoutes], base? : String) -> Array[CompiledSolRoute]

    Compile SolRoutes to optimized format

    error_response

    fn error_response(message : String, status? : Int) -> ApiResponse

    Create an error response

    extract_dynamic_patterns

    fn extract_dynamic_patterns(routes : Array[SolRoutes]) -> Array[String]

    Extract dynamic route patterns for run_worker_first

    forbidden

    fn forbidden(message? : String) -> ApiResponse

    Create a forbidden (403) response

    generate_wrangler_assets_config

    fn generate_wrangler_assets_config(routes : Array[SolRoutes], output_dir : String) -> String

    Generate wrangler.json assets config fragment

    manifest_to_sol_routes

    fn manifest_to_sol_routes(manifest :
    RouteManifest
    , page_factory : PageHandlerFactory, api_factory : ApiHandlerFactory) -> Array[SolRoutes]

    Convert RouteManifest to SolRoutes with handler injection

    This allows external modules (like Sol SSG) to inject content processing by providing factory functions that create handlers from route metadata.

    Example usage:
    let manifest = scan_pages_dir(fs, "docs", cwd) let routes = manifest_to_sol_routes(manifest, my_page_factory, my_api_factory) register_sol_routes(app, routes, config)

    nodes

    Create a sync ServerNode from an array of nodes

    Example:
    nodes([
    @element.h1([@element.text("Hello")]),
    @element.p([@element.text("World")]),
    ])

    not_found_response

    fn not_found_response(message? : String) -> ApiResponse

    Create a 404 not found response

    null_api_factory

    fn null_api_factory() -> ApiHandlerFactory

    Create an API factory that always returns None (fallback/null factory)

    null_page_factory

    fn null_page_factory() -> PageHandlerFactory

    Create a page factory that always returns None (fallback/null factory)
    fn ok(pairs : Array[(String, Json)]) -> ApiResponse

    Create a JSON response from key-value pairs

    Example:
    ok([("status", "ok".to_json())]).to_json()

    optional

    fn optional(props : PageProps, name : String, default : String) -> String

    Extract an optional path parameter with default value (delegates to RouteParams)

    optional_query

    fn optional_query(props : PageProps, name : String, default : String) -> String

    Extract an optional query parameter with default value (delegates to RouteParams)

    page

    fn page(path : String, handler : async (PageProps) ->
    ServerNode
    , title? : String, meta? : Array[(String, String)], revalidate? : Int?, cache? : CacheStrategy?) -> SolRoutes

    Create a page route with minimal boilerplate

    Example:
    page("/", home, title="Home")
    page("/blog/:slug", blog_post, title="Blog", revalidate=Some(60))

    redirect_permanent_to

    fn redirect_permanent_to(url : String) -> ApiResponse

    Create a permanent redirect (301)

    redirect_to

    fn redirect_to(url : String, status? : Int) -> ApiResponse

    Create a redirect response (default 302)

    register_mbtx_routes

    fn register_mbtx_routes(app :
    Server
    , routes : Array[MbtxRoute]) -> Unit

    Register .mbtx routes to the app. Each route calls the pre-loaded render() function from the ESM module.

    register_routes

    fn[E] register_routes(app :
    Server
    , routes : Array[
    Routes
    ], page_resolver : (String,
    Context
    , RouteParams) ->
    Node
    [E, String]?, api_resolver : (String,
    Context
    , RouteParams) ->
    Any
    ?, config? : RouterConfig, title_prefix? : String, default_title? : String, default_head? : String, loader_url? : String, wc_loader_url? : String) -> Unit

    Register routes from Routes definition to Hono app Uses a resolver function to map component IDs to render functions @deprecated Use register_sol_routes instead

    register_server_routes

    fn register_server_routes(app :
    Server
    , routes : Array[
    Routes
    ], page_resolver : (String,
    Context
    , RouteParams) ->
    ServerNode
    ?, api_resolver : (String,
    Context
    , RouteParams) ->
    Any
    ?, config? : RouterConfig, title_prefix? : String, default_title? : String, default_head? : String, loader_url? : String, wc_loader_url? : String) -> Unit

    Register routes with async server component support Uses ServerNode which supports both sync and async server components @deprecated Use register_sol_routes instead

    register_sol_routes

    fn register_sol_routes(app :
    Server
    , routes : Array[SolRoutes], config? : RouterConfig) -> Unit

    Register Sol routes to Hono app

    render_fragment_response

    fn[E] render_fragment_response(node :
    Node
    [E, String], title : String, hydration : Bool) -> String

    Extract outlets from rendered HTML and wrap in templates This function takes the full page HTML and extracts elements with data-sol-outlet attributes, wrapping each in a template.

    require

    fn require(props : PageProps, name : String) -> Result[String, ApiResponse]

    Extract a required path parameter (delegates to RouteParams)

    require_int

    fn require_int(props : PageProps, name : String) -> Result[Int, ApiResponse]

    Extract and parse an integer parameter (delegates to RouteParams)

    require_query

    fn require_query(props : PageProps, name : String) -> Result[String, ApiResponse]

    Extract a required query parameter (delegates to RouteParams)

    send_fragment_response

    async fn send_fragment_response(c :
    Context
    , html : String) -> Unit

    Send fragment response with appropriate headers

    sol_routes_to_manifest

    fn sol_routes_to_manifest(routes : Array[SolRoutes], base? : String) ->
    RouteManifest

    Convert SolRoutes array to RouteManifest

    split_mbtx_chunks

    fn split_mbtx_chunks(entries : Array[MbtxEntry], shared_path? : String) -> MbtxChunkResult

    Extract shared declarations across multiple .mbtx JS outputs. Declarations appearing in 2+ files are moved to a shared module. Each entry is rewritten to import from the shared module.

    transform_mbtx_to_esm

    fn transform_mbtx_to_esm(code : String) -> String

    Transform a built .mbtx JS (IIFE) into an ESM module with render() export. Input: standard moonc output with (() => { ... })() at the end Output: same code but IIFE replaced with export default function render(env) { ... }

    unauthorized

    fn unauthorized(message? : String) -> ApiResponse

    Create an unauthorized (401) response

    with_mw

    Apply middleware to a group of routes

    Example:
    with_mw([@mw.logger(), @mw.cors()], [
    api_get("/api/data", get_data),
    ])

    wrap

    Create a layout wrapper

    Example:
    wrap("/admin", admin_layout, [
    page("/", admin_dashboard),
    page("/settings", admin_settings),
    ])