Files
narl-workspace/src/static_files.rs
T
nvrl 4002a35305 Terminal-themed markdown diary
Single-user diary served as one Rust binary with the Svelte frontend
embedded.

- axum 0.8 + SQLite (sqlx), migrations run at startup
- stateless HMAC session cookie; credentials from .env, compared in
  constant time
- FTS5 full-text search, user input rewritten into quoted prefix terms
- media uploads linked to entries by scanning bodies for /api/media/<id>,
  which scopes share-token media access and entry deletion
- unguessable share links (192-bit token) serving a public read-only page
- vim keybindings via CodeMirror plus a modal browse layer and : command
  line; disabled on touch devices
2026-09-05 05:39:25 +02:00

46 lines
1.4 KiB
Rust

use axum::{
http::{header, StatusCode, Uri},
response::{IntoResponse, Response},
};
use rust_embed::Embed;
/// The built Svelte app. In debug builds rust-embed reads from disk, so a
/// `vite build --watch` next to `cargo run` is enough for iteration.
#[derive(Embed)]
#[folder = "$CARGO_MANIFEST_DIR/web/dist"]
struct Assets;
pub async fn handler(uri: Uri) -> Response {
let path = uri.path().trim_start_matches('/');
match Assets::get(path) {
Some(file) => serve(path, file),
// Unknown paths are client-side routes; hand them the shell.
None => match Assets::get("index.html") {
Some(index) => serve("index.html", index),
None => (
StatusCode::NOT_FOUND,
"frontend not built - run `bun run build` in web/",
)
.into_response(),
},
}
}
fn serve(path: &str, file: rust_embed::EmbeddedFile) -> Response {
let mime = mime_guess::from_path(path).first_or_octet_stream();
// Vite fingerprints everything under /assets/, so it is safe to cache hard.
let cache = if path.starts_with("assets/") {
"public, max-age=31536000, immutable"
} else {
"no-cache"
};
(
[
(header::CONTENT_TYPE, mime.as_ref()),
(header::CACHE_CONTROL, cache),
],
file.data,
)
.into_response()
}