diff --git a/Cargo.toml b/Cargo.toml
index 3603e64..3d7ac96 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ axum = { version = "0.8", features = ["multipart"], optional = true }
aws-sdk-s3 = { version = "1", optional = true }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal"], optional = true }
tower = { version = "0.5", optional = true }
-tower-http = { version = "0.6", features = ["fs"], optional = true }
+tower-http = { version = "0.6", features = ["fs", "set-header"], optional = true }
tower-sessions = { version = "0.14", optional = true }
async-nats = { version = "0.38", optional = true }
arc-swap = { version = "1", optional = true }
diff --git a/src/app.rs b/src/app.rs
index 1fc9633..5daa6f3 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -89,6 +89,18 @@ fn QuestionPage() -> impl IntoView {
let site = Resource::new(|| (), |_| get_site());
view! {
+ // The content-declared site title lives OUTSIDE the question
+ // Suspense: tied to the per-page resource it unmounted on every
+ // SPA navigation and lost the leptos_meta race to App's
+ // compile-time SITE_NAME fallback (redoal.com flashing to
+ // "uhhm" on nav - and staying there). Out here it mounts once
+ // and covers every branch, NotFound included.
+ {move || {
+ site.get()
+ .and_then(|r| r.ok())
+ .and_then(|s| s.title)
+ .map(|t| view! {
})
+ }}
@@ -109,13 +121,6 @@ fn QuestionPage() -> impl IntoView {
Ok(Some(page)) => {
let current = user_res.and_then(|r| r.ok()).flatten();
view! {
- // A second outranks App's
- // SITE_NAME fallback only when content
- // actually declares one.
- {site_cfg
- .title
- .clone()
- .map(|t| view! { })}
anyhow::Result<()> {
.route("/upload", post(upload::upload))
.route("/gitea-repo", get(content::gitea_repo_handler))
.route("/automation/kv/{bucket}", get(content::automation_kv_handler))
- .nest_service("/pkg", ServeDir::new(pkg_dir))
+ // no-cache = "revalidate before reuse", not "don't cache":
+ // pkg files keep the same names across releases (portal.js,
+ // portal.wasm), and without this browsers heuristically cache
+ // them - a stale wasm from the previous release then talks to
+ // a server whose server-fn wire format has moved on and every
+ // page renders as its error branch. A 304 per load is the
+ // price of never shipping that skew again.
+ .nest_service(
+ "/pkg",
+ tower::ServiceBuilder::new()
+ .layer(tower_http::set_header::SetResponseHeaderLayer::overriding(
+ axum::http::header::CACHE_CONTROL,
+ axum::http::HeaderValue::from_static("no-cache"),
+ ))
+ .service(ServeDir::new(pkg_dir)),
+ )
.nest_service("/fonts", ServeDir::new(fonts_dir))
.route_service("/favicon-light.svg", ServeFile::new(favicon_light_path))
.route_service("/favicon-dark.svg", ServeFile::new(favicon_dark_path))
@@ -152,7 +167,17 @@ async fn main() -> anyhow::Result<()> {
"/swiper-element-bundle.min.js",
ServeFile::new(swiper_path),
)
- .route_service("/yes.js", ServeFile::new(yes_path))
+ // Same skew concern as /pkg: the wasm's raw_module import and
+ // the hero's inline script both load this by fixed name.
+ .route_service(
+ "/yes.js",
+ tower::ServiceBuilder::new()
+ .layer(tower_http::set_header::SetResponseHeaderLayer::overriding(
+ axum::http::header::CACHE_CONTROL,
+ axum::http::HeaderValue::from_static("no-cache"),
+ ))
+ .service(ServeFile::new(yes_path)),
+ )
.leptos_routes_with_context(
&state,
routes,