3 Commits
Author SHA1 Message Date
sbstp 1291c5a33a embed assets and version 0.1.2
ci/woodpecker/push/e2e Pipeline was successful
ci/woodpecker/push/fmt Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
2026-08-02 21:28:54 -04:00
sbstp d6c31375ae version 0.1.1 [skip ci]
ci/woodpecker/tag/release Pipeline was successful
2026-08-02 20:42:12 -04:00
sbstp a014ffc602 fix release ci [skip ci] 2026-08-02 20:41:38 -04:00
4 changed files with 22 additions and 17 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ steps:
build: build:
image: rust:1 image: rust:1
commands: commands:
- cargo run --release - cargo build --release
publish: publish:
image: alpine:3.23 image: alpine:3.23
Generated
+1 -1
View File
@@ -1460,7 +1460,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "sustenance" name = "sustenance"
version = "0.1.0" version = "0.1.2"
dependencies = [ dependencies = [
"argon2", "argon2",
"async-trait", "async-trait",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "sustenance" name = "sustenance"
version = "0.1.0" version = "0.1.2"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
+19 -14
View File
@@ -16,11 +16,7 @@ use axum::{
use futures_util::{SinkExt, StreamExt}; use futures_util::{SinkExt, StreamExt};
use serde::{Deserialize, de::DeserializeOwned}; use serde::{Deserialize, de::DeserializeOwned};
use thiserror::Error; use thiserror::Error;
use tower_http::{ use tower_http::trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer};
services::ServeDir,
set_header::SetResponseHeaderLayer,
trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer},
};
use tracing::{Level, error, warn}; use tracing::{Level, error, warn};
use crate::domain::{DomainError, SessionUser}; use crate::domain::{DomainError, SessionUser};
@@ -29,6 +25,12 @@ use crate::services::{AuthService, InvitationService, ListService, MealService};
use crate::views; use crate::views;
use crate::webauthn::WebAuthnService; use crate::webauthn::WebAuthnService;
/// The contents of `static/`, embedded into the binary at compile time so the
/// app can be shipped as a single executable without a separate static directory.
const STYLE_CSS: &[u8] = include_bytes!("../static/style.css");
const PASSKEY_LOGIN_JS: &[u8] = include_bytes!("../static/passkey-login.js");
const PASSKEY_REGISTER_JS: &[u8] = include_bytes!("../static/passkey-register.js");
#[derive(Clone)] #[derive(Clone)]
pub struct AppState { pub struct AppState {
pub auth: Arc<AuthService>, pub auth: Arc<AuthService>,
@@ -116,15 +118,7 @@ pub fn build_router(state: AppState) -> Router {
.route("/lists/{list_id}/stream", get(list_stream)) .route("/lists/{list_id}/stream", get(list_stream))
.route("/invite/{token}", get(invitation_page)) .route("/invite/{token}", get(invitation_page))
.route("/invite/{token}/accept", post(accept_invitation)) .route("/invite/{token}/accept", post(accept_invitation))
.nest_service( .route("/static/{path}", get(static_asset))
"/static",
tower::ServiceBuilder::new()
.layer(SetResponseHeaderLayer::overriding(
header::CACHE_CONTROL,
HeaderValue::from_static("public, max-age=0, must-revalidate"),
))
.service(ServeDir::new("static")),
)
.layer( .layer(
TraceLayer::new_for_http() TraceLayer::new_for_http()
.make_span_with(DefaultMakeSpan::new().level(Level::INFO)) .make_span_with(DefaultMakeSpan::new().level(Level::INFO))
@@ -313,6 +307,17 @@ async fn home() -> Redirect {
Redirect::to("/lists") Redirect::to("/lists")
} }
/// Serves a file embedded in the binary from the `static/` folder.
async fn static_asset(Path(path): Path<String>) -> Response {
let (mime, data) = match path.as_str() {
"style.css" => ("text/css", STYLE_CSS),
"passkey-login.js" => ("application/javascript", PASSKEY_LOGIN_JS),
"passkey-register.js" => ("application/javascript", PASSKEY_REGISTER_JS),
_ => return StatusCode::NOT_FOUND.into_response(),
};
([(header::CONTENT_TYPE, mime)], data).into_response()
}
async fn log_response_status(request: Request, next: Next) -> Response { async fn log_response_status(request: Request, next: Next) -> Response {
let method = request.method().clone(); let method = request.method().clone();
let uri = request.uri().clone(); let uri = request.uri().clone();