diff --git a/engine/packages/api-public/src/router.rs b/engine/packages/api-public/src/router.rs index 942c7b48c2..bf018808e7 100644 --- a/engine/packages/api-public/src/router.rs +++ b/engine/packages/api-public/src/router.rs @@ -121,6 +121,7 @@ pub async fn router( .route("/ui", axum::routing::get(ui::serve_index)) .route("/ui/", axum::routing::get(ui::serve_index)) .route("/ui/{*path}", axum::routing::get(ui::serve_ui)) + .route("/assets/{*path}", axum::routing::get(ui::serve_asset)) // MARK: Middleware (must go after all routes) // Add CORS layer that mirrors the request origin .layer( @@ -170,6 +171,7 @@ async fn auth_middleware( && path != "/" && path != "/ui" && !path.starts_with("/ui/") + && !path.starts_with("/assets/") && !ctx.is_auth_handled() { return Err(( diff --git a/engine/packages/api-public/src/ui.rs b/engine/packages/api-public/src/ui.rs index e638ffe50e..d9b7f6db7c 100644 --- a/engine/packages/api-public/src/ui.rs +++ b/engine/packages/api-public/src/ui.rs @@ -20,25 +20,38 @@ pub async fn serve_index() -> Response { pub async fn serve_ui(Path(path): Path) -> Response { let file_path = path.trim_start_matches('/'); - if let Some(file) = UI_DIR.get_file(file_path) { - let content_type = match file_path.split('.').last() { - Some("html") => "text/html", - Some("css") => "text/css", - Some("js") => "application/javascript", - Some("json") => "application/json", - Some("png") => "image/png", - Some("jpg") | Some("jpeg") => "image/jpeg", - Some("svg") => "image/svg+xml", - Some("ico") => "image/x-icon", - Some("woff") => "font/woff", - Some("woff2") => "font/woff2", - Some("ttf") => "font/ttf", - Some("eot") => "application/vnd.ms-fontobject", - _ => "application/octet-stream", - }; - - ([(header::CONTENT_TYPE, content_type)], file.contents()).into_response() + if let Some(res) = serve_file(file_path) { + res } else { serve_index().await } } + +#[tracing::instrument(skip_all)] +pub async fn serve_asset(Path(path): Path) -> Response { + let file_path = format!("assets/{}", path.trim_start_matches('/')); + + serve_file(&file_path).unwrap_or_else(|| StatusCode::NOT_FOUND.into_response()) +} + +fn serve_file(file_path: &str) -> Option { + let file = UI_DIR.get_file(file_path)?; + + let content_type = match file_path.split('.').last() { + Some("html") => "text/html", + Some("css") => "text/css", + Some("js") => "application/javascript", + Some("json") => "application/json", + Some("png") => "image/png", + Some("jpg") | Some("jpeg") => "image/jpeg", + Some("svg") => "image/svg+xml", + Some("ico") => "image/x-icon", + Some("woff") => "font/woff", + Some("woff2") => "font/woff2", + Some("ttf") => "font/ttf", + Some("eot") => "application/vnd.ms-fontobject", + _ => "application/octet-stream", + }; + + Some(([(header::CONTENT_TYPE, content_type)], file.contents()).into_response()) +}