- 1
//! The workspace client, served at `/app` (docs/design/48-web-client.md). - 2
//! - 3
//! Same bundle as the Tauri desktop shell ships — one client, two hosts — - 4
//! built a second time with `base: "/app/"` so its asset URLs resolve here - 5
//! (`crates/vak-client-ui`, `npm run build:web` → `dist-web/`). - 6
//! - 7
//! The shell and its hashed assets are auth-exempt because the login form - 8
//! is part of the bundle: a browser has to be able to load the page in - 9
//! order to be asked for a token. Nothing here carries data — every route - 10
//! the client then calls is authenticated. - 11
- 12
use axum::routing::get; - 13
use include_dir::{Dir, include_dir}; - 14
- 15
use crate::embedded_ui::{register_files, serve_file}; - 16
- 17
static CLIENT_UI: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../vak-client-ui/dist-web"); - 18
- 19
async fn index() -> axum::response::Response { - 20
serve_file(&CLIENT_UI, "index.html") - 21
} - 22
- 23
pub(crate) fn routes() -> axum::Router<crate::AppState> { - 24
let router = axum::Router::new() - 25
.route("/app", get(index)) - 26
.route("/app/", get(index)) - 27
// The client uses hash routing, so there are no deep paths to - 28
// rewrite — but a bookmark to `/app/anything` should still land on - 29
// the shell rather than a bare 404 from the router. - 30
.route("/app/{*rest}", get(index)); - 31
register_files(router, &CLIENT_UI, &CLIENT_UI, "/app") - 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
/// The `/admin` version of this test exists because the failure it - 41
/// catches shipped three times. `/app` is served by the same code, so - 42
/// it gets the same proof rather than the same trust. - 43
#[test] - 44
fn every_asset_index_html_references_is_actually_embedded() { - 45
let referenced = referenced_assets(&CLIENT_UI, "/app"); - 46
assert!( - 47
!referenced.is_empty(), - 48
"index.html references no /app/assets/ paths — either the web bundle was \ - 49
built without `base: /app/`, or this extraction no longer matches the markup" - 50
); - 51
for url_path in referenced { - 52
let embedded_path = url_path.trim_start_matches("/app/"); - 53
assert!( - 54
CLIENT_UI.get_file(embedded_path).is_some(), - 55
"index.html references {url_path}, but no such file is embedded" - 56
); - 57
} - 58
} - 59
- 60
#[tokio::test] - 61
async fn every_referenced_asset_is_actually_routable() { - 62
use http_body_util::BodyExt as _; - 63
use tower::ServiceExt as _; - 64
- 65
let referenced = referenced_assets(&CLIENT_UI, "/app"); - 66
assert!(!referenced.is_empty(), "nothing to check"); - 67
- 68
for url_path in referenced { - 69
let router = routes().with_state(crate::test_support::state()); - 70
let response = router - 71
.oneshot( - 72
axum::http::Request::builder() - 73
.uri(&url_path) - 74
.body(axum::body::Body::empty()) - 75
.unwrap(), - 76
) - 77
.await - 78
.unwrap(); - 79
assert_eq!( - 80
response.status(), - 81
axum::http::StatusCode::OK, - 82
"GET {url_path} did not route to 200" - 83
); - 84
let bytes = response.into_body().collect().await.unwrap().to_bytes(); - 85
assert!( - 86
!bytes.is_empty(), - 87
"GET {url_path} routed but returned nothing" - 88
); - 89
} - 90
} - 91
- 92
/// A bookmarked deep link must reach the shell, not a 404 — the client - 93
/// routes on the hash, but nothing stops someone pasting a path. - 94
#[tokio::test] - 95
async fn a_deep_path_serves_the_shell() { - 96
use tower::ServiceExt as _; - 97
let router = routes().with_state(crate::test_support::state()); - 98
let response = router - 99
.oneshot( - 100
axum::http::Request::builder() - 101
.uri("/app/w/abc/s/def") - 102
.body(axum::body::Body::empty()) - 103
.unwrap(), - 104
) - 105
.await - 106
.unwrap(); - 107
assert_eq!(response.status(), axum::http::StatusCode::OK); - 108
} - 109
} - 110
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.