- 1
//! Embedded admin SPA (crates/vak-admin-ui/dist). The frontend is a static - 2
//! SolidJS bundle; every data call goes through the authenticated - 3
//! /admin/api/* routes in `crate::admin`. Serving is read-only and - 4
//! stateless — no session state lives here, auth rides the cookie. - 5
//! - 6
//! The serving mechanics are shared with the workspace client at `/app`; - 7
//! see `crate::embedded_ui` for why they live in one place. - 8
- 9
use axum::routing::get; - 10
use include_dir::{Dir, include_dir}; - 11
- 12
use crate::embedded_ui::{register_files, serve_file}; - 13
- 14
static ADMIN_UI: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../vak-admin-ui/dist"); - 15
- 16
async fn index() -> axum::response::Response { - 17
serve_file(&ADMIN_UI, "index.html") - 18
} - 19
- 20
pub(crate) fn routes() -> axum::Router<crate::AppState> { - 21
let router = axum::Router::new() - 22
.route("/admin", get(index)) - 23
.route("/admin/", get(index)) - 24
// dist/favicon.svg is served by register_files below at - 25
// /admin/favicon.svg; the bare /favicon.svg alias is registered - 26
// here since it lives outside that prefix. - 27
.route( - 28
"/favicon.svg", - 29
get(|| async { serve_file(&ADMIN_UI, "favicon.svg") }), - 30
); - 31
register_files(router, &ADMIN_UI, &ADMIN_UI, "/admin") - 32
} - 33
- 34
#[cfg(test)] - 35
#[allow(clippy::unwrap_used, clippy::expect_used)] - 36
mod tests { - 37
use super::*; - 38
use crate::embedded_ui::referenced_assets; - 39
- 40
/// Every asset `index.html` references by URL must actually be - 41
/// embedded, or the admin console loads a blank shell with nothing - 42
/// in the console to say why: no JS runs, so nothing errors. - 43
/// - 44
/// This is the same failure `crates/vak-server/build.rs` exists to - 45
/// prevent — `include_dir!` has no way to know dist/ is a build - 46
/// input unless a build script says so, and without one a `cargo - 47
/// build` after `npm run build` could reuse an incremental build of - 48
/// this crate from before the rebuild, silently embedding an - 49
/// `index.html` that references hashed filenames the embedded - 50
/// directory no longer contains. That shipped as part of v0.8.1. - 51
#[test] - 52
fn every_asset_index_html_references_is_actually_embedded() { - 53
let referenced = referenced_assets(&ADMIN_UI, "/admin"); - 54
assert!( - 55
!referenced.is_empty(), - 56
"index.html references no /admin/assets/ paths — the extraction above is not \ - 57
matching this build's markup, not evidence there is nothing to check" - 58
); - 59
for url_path in referenced { - 60
let embedded_path = url_path.trim_start_matches("/admin/"); - 61
assert!( - 62
ADMIN_UI.get_file(embedded_path).is_some(), - 63
"index.html references {url_path}, but no such file is embedded — \ - 64
this is the exact defect that shipped in v0.8.1" - 65
); - 66
} - 67
} - 68
- 69
/// The test above checks embedding; this checks routing — a - 70
/// different layer, and the one that was actually broken. - 71
/// `Dir::files()` is not recursive, so the previous route - 72
/// registration loop never reached anything under `assets/`. - 73
#[tokio::test] - 74
async fn every_referenced_asset_is_actually_routable() { - 75
use http_body_util::BodyExt as _; - 76
use tower::ServiceExt as _; - 77
- 78
let referenced = referenced_assets(&ADMIN_UI, "/admin"); - 79
assert!( - 80
!referenced.is_empty(), - 81
"nothing to check — extraction is not matching this markup" - 82
); - 83
- 84
for url_path in referenced { - 85
let router = routes().with_state(crate::test_support::state()); - 86
let response = router - 87
.oneshot( - 88
axum::http::Request::builder() - 89
.uri(&url_path) - 90
.body(axum::body::Body::empty()) - 91
.unwrap(), - 92
) - 93
.await - 94
.unwrap(); - 95
assert_eq!( - 96
response.status(), - 97
axum::http::StatusCode::OK, - 98
"GET {url_path} did not route to 200 — this is the exact defect \ - 99
that shipped in v0.8.1, v0.8.2, and v0.8.3's first attempt at fixing it" - 100
); - 101
let bytes = response.into_body().collect().await.unwrap().to_bytes(); - 102
assert!( - 103
!bytes.is_empty(), - 104
"GET {url_path} routed but returned an empty body" - 105
); - 106
} - 107
} - 108
} - 109
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.